SlideShare a Scribd company logo
1 of 68
Download to read offline
ProGuard
Optimizer and Obfuscator
in the Android SDK
Eric Lafortune
Developer of ProGuard
Technical director at Saikoa
Topics
ProGuard
– Techniques
– Results
More application protection
– Goals
– Attackers
– Types of attacks
– Protection
ProGuard
Open source
Generic
Shrinker
Optimizer
Obfuscator
For Java bytecode
ProGuard history
Java 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
ProGuard
Application
code
Shrink
Libraries
Android
runtime
Optimize Obfuscate
Processed
code
Android
runtime
ProGuard in Android builds
Application
Java bytecode
ProGuard
Libraries
Java bytecode
Processed
Java bytecode Dex
Dalvik bytecode
Javac
Application
Java source
Libraries
Java bytecode
XML resources
Assets Assets
Compiled
XML resourcesAapt
Why use ProGuard?
●
Application size
●
Performance
●
Remove logging, debugging, testing code
●
Protection
Application size
classes.dex size .apk size
Without
ProGuard
With
ProGuard
Reduction
ApiDemos 716 K 482 K 33 % 2.6 M 2.5 M 4 %
GoogleIO
App
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]
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]
Battery life
Extreme example:
“5 x better battery life,
by removing verbose logging code
in a background service”
(but don't count on it)
Results
●
Size reduction:
– Code (classes.dex): 20 … 90%
– Application (.apk): 5 ... 70%
●
Performance improvements: 0 … 20%
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
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
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.JSONArray
Warning: 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.Logger
Warning: 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.Logger
Warning: twitter4j.internal.logging.SLF4JLoggerFactory:
can't find referenced class org.slf4j.LoggerFactory
...
Tip
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
Shrinking
Also called treeshaking, minimizing, shrouding
Shrinking
●
Classes, fields, methods
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
…
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
Optimization
At the bytecode instruction level:
●
Dead code elimination
●
Constant propagation
●
Method inlining
●
Class merging
●
Remove logging code
●
Peephole optimizations
●
Devirtualization
●
...
Optimization example
int 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);
}
}
Optimization example
int 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);
}
Optimization example
int 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
Optimization example
int 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;
}
Optimization example
int 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;
Optimization: enum
int 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
Optimization: enum
int 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
Optimization: enum
int 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;
}
}
Optimization: enum
int 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;
}
}
Optimization: enum
int 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;
}
}
Optimization: enum
int 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;
How to enable optimization?
Ant and Eclipse: project.properties
# To enable ProGuard to shrink and obfuscate
your code, uncomment this
proguard.config=
${sdk.dir}/tools/proguard/proguard-android-optimize.txt:
proguard-project.txt
# To enable ProGuard to shrink and obfuscate
your code, uncomment this
proguard.config=
${sdk.dir}/tools/proguard/proguard-android-optimize.txt:
proguard-project.txt
Tip
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
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
Obfuscation
Traditional name obfuscation:
●
Rename identifiers:
class/field/method names
●
Remove debug information:
line numbers, local variable names,...
Obfuscation example
public 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;
}
}
Obfuscation example
public 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;
}
}
Complementary steps
Optimization Obfuscation
Irreversibly remove information
What about ART?
The new (experimental) Android RunTime
Application
Java bytecode
ProGuard
Libraries
Java bytecode
Processed
Java bytecode Dex
Dalvik bytecode
Dex2oat
Native code
Development
Device
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”);
}
}
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”);
}
}
More application protection
●
Goals
●
Attackers
●
Types of attacks
●
Protection
What to protect?
●
Application
●
Algorithms
●
Communication
●
Assets
●
Keys
Code
Resources
Assets
Signatures
Attackers
Attackers
Time
Choice
Static analysis
Static analysis
●
Disassemblers: dexdump, baksmali
●
Decompilers: dex2jar + jad, JD-GUI, JEB,...
●
Resources: aapt, apktool,...
Dynamic analysis
Dynamic analysis
●
Debuggers: adb,...
●
Subverted runtime
●
Cracking tools
Server-side code
Client-side
application
Server-side
application
?
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=”));
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!” });
Dynamic class loading
http://android-developers.blogspot.be/2011/07/custom-class-loading-in-dalvik.html
classes.dex
extra.dex
classes.dex
libutil.so
libutil.so
Native code
Java Native Interface
classes.dex
libutil.so
classes.dex
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);
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;
}
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();
Environment checks
●
Emulator detection
●
Root detection
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
DexGuard
●
Specialized for Android
●
Code and data
●
Layers of protection
●
Recommended techniques
●
Low-level techniques
●
Transparent
Tip
Code
Resources
Assets
Signatures
ProGuard - DexGuard
Open source
Generic
Shrinker
Optimizer
Obfuscator
For Java bytecode
Closed source
Specialized
Shrinker
Optimizer
Obfuscator
Protector
For Android
Compatible
ProGuard guide – Android SDK
developer.android.comdeveloper.android.com
ProGuard website
proguard.sourceforge.netproguard.sourceforge.net
ProGuard manual
proguard.sourceforge.netproguard.sourceforge.net
Tip
Saikoa website
www.saikoa.comwww.saikoa.com
Questions?
Open source
Shrinking
Optimization
Obfuscation
Java bytecode
ProGuard
Saikoa
DexGuard
Dalvik bytecode
Protection

More Related Content

What's hot

Tools and Techniques for Understanding Threading Behavior in Android*
Tools and Techniques for Understanding Threading Behavior in Android*Tools and Techniques for Understanding Threading Behavior in Android*
Tools and Techniques for Understanding Threading Behavior in Android*Intel® Software
 
Scientific calcultor-Java
Scientific calcultor-JavaScientific calcultor-Java
Scientific calcultor-JavaShaibal Ahmed
 
20130530-PEGjs
20130530-PEGjs20130530-PEGjs
20130530-PEGjszuqqhi 2
 
Navigating the xDD Alphabet Soup
Navigating the xDD Alphabet SoupNavigating the xDD Alphabet Soup
Navigating the xDD Alphabet SoupDror Helper
 
Simulado java se 7 programmer
Simulado java se 7 programmerSimulado java se 7 programmer
Simulado java se 7 programmerMiguel Vilaca
 
A proposal of the OpenFlow controller development support tool
A proposal of the OpenFlow controller development support tool A proposal of the OpenFlow controller development support tool
A proposal of the OpenFlow controller development support tool Yutaka Yasuda
 
Mutation Testing at BzhJUG
Mutation Testing at BzhJUGMutation Testing at BzhJUG
Mutation Testing at BzhJUGSTAMP Project
 
C++ game development with oxygine
C++ game development with oxygineC++ game development with oxygine
C++ game development with oxyginecorehard_by
 
Applying Compiler Techniques to Iterate At Blazing Speed
Applying Compiler Techniques to Iterate At Blazing SpeedApplying Compiler Techniques to Iterate At Blazing Speed
Applying Compiler Techniques to Iterate At Blazing SpeedPascal-Louis Perez
 
The Ring programming language version 1.2 book - Part 59 of 84
The Ring programming language version 1.2 book - Part 59 of 84The Ring programming language version 1.2 book - Part 59 of 84
The Ring programming language version 1.2 book - Part 59 of 84Mahmoud Samir Fayed
 
Improving Android Performance at Droidcon UK 2014
Improving Android Performance at Droidcon UK 2014Improving Android Performance at Droidcon UK 2014
Improving Android Performance at Droidcon UK 2014Raimon Ràfols
 
Test-driven JavaScript Development - OPITZ CONSULTING - Tobias Bosch - Stefa...
Test-driven JavaScript Development - OPITZ CONSULTING -  Tobias Bosch - Stefa...Test-driven JavaScript Development - OPITZ CONSULTING -  Tobias Bosch - Stefa...
Test-driven JavaScript Development - OPITZ CONSULTING - Tobias Bosch - Stefa...OPITZ CONSULTING Deutschland
 
Java PRACTICAL file
Java PRACTICAL fileJava PRACTICAL file
Java PRACTICAL fileRACHIT_GUPTA
 
Some stuff about C++ and development
Some stuff about C++ and developmentSome stuff about C++ and development
Some stuff about C++ and developmentJon Jagger
 
12. Java Exceptions and error handling
12. Java Exceptions and error handling12. Java Exceptions and error handling
12. Java Exceptions and error handlingIntro C# Book
 

What's hot (20)

Tools and Techniques for Understanding Threading Behavior in Android*
Tools and Techniques for Understanding Threading Behavior in Android*Tools and Techniques for Understanding Threading Behavior in Android*
Tools and Techniques for Understanding Threading Behavior in Android*
 
Qe Reference
Qe ReferenceQe Reference
Qe Reference
 
Scientific calcultor-Java
Scientific calcultor-JavaScientific calcultor-Java
Scientific calcultor-Java
 
20130530-PEGjs
20130530-PEGjs20130530-PEGjs
20130530-PEGjs
 
Navigating the xDD Alphabet Soup
Navigating the xDD Alphabet SoupNavigating the xDD Alphabet Soup
Navigating the xDD Alphabet Soup
 
Computer Programming- Lecture 4
Computer Programming- Lecture 4Computer Programming- Lecture 4
Computer Programming- Lecture 4
 
Simulado java se 7 programmer
Simulado java se 7 programmerSimulado java se 7 programmer
Simulado java se 7 programmer
 
A proposal of the OpenFlow controller development support tool
A proposal of the OpenFlow controller development support tool A proposal of the OpenFlow controller development support tool
A proposal of the OpenFlow controller development support tool
 
E:\Plp 2009 2\Plp 9
E:\Plp 2009 2\Plp 9E:\Plp 2009 2\Plp 9
E:\Plp 2009 2\Plp 9
 
Mutation Testing at BzhJUG
Mutation Testing at BzhJUGMutation Testing at BzhJUG
Mutation Testing at BzhJUG
 
C++ game development with oxygine
C++ game development with oxygineC++ game development with oxygine
C++ game development with oxygine
 
Applying Compiler Techniques to Iterate At Blazing Speed
Applying Compiler Techniques to Iterate At Blazing SpeedApplying Compiler Techniques to Iterate At Blazing Speed
Applying Compiler Techniques to Iterate At Blazing Speed
 
Lecture 12: Classes and Files
Lecture 12: Classes and FilesLecture 12: Classes and Files
Lecture 12: Classes and Files
 
Kpi driven-java-development-fn conf
Kpi driven-java-development-fn confKpi driven-java-development-fn conf
Kpi driven-java-development-fn conf
 
The Ring programming language version 1.2 book - Part 59 of 84
The Ring programming language version 1.2 book - Part 59 of 84The Ring programming language version 1.2 book - Part 59 of 84
The Ring programming language version 1.2 book - Part 59 of 84
 
Improving Android Performance at Droidcon UK 2014
Improving Android Performance at Droidcon UK 2014Improving Android Performance at Droidcon UK 2014
Improving Android Performance at Droidcon UK 2014
 
Test-driven JavaScript Development - OPITZ CONSULTING - Tobias Bosch - Stefa...
Test-driven JavaScript Development - OPITZ CONSULTING -  Tobias Bosch - Stefa...Test-driven JavaScript Development - OPITZ CONSULTING -  Tobias Bosch - Stefa...
Test-driven JavaScript Development - OPITZ CONSULTING - Tobias Bosch - Stefa...
 
Java PRACTICAL file
Java PRACTICAL fileJava PRACTICAL file
Java PRACTICAL file
 
Some stuff about C++ and development
Some stuff about C++ and developmentSome stuff about C++ and development
Some stuff about C++ and development
 
12. Java Exceptions and error handling
12. Java Exceptions and error handling12. Java Exceptions and error handling
12. Java Exceptions and error handling
 

Viewers also liked

Portes ouvertes Innov'Action 2016 Morbihan - CUMA de Questembert
Portes ouvertes Innov'Action 2016 Morbihan - CUMA de QuestembertPortes ouvertes Innov'Action 2016 Morbihan - CUMA de Questembert
Portes ouvertes Innov'Action 2016 Morbihan - CUMA de QuestembertChambres d'agriculture de Bretagne
 
Ci 350 assure method thursday
Ci 350 assure method thursdayCi 350 assure method thursday
Ci 350 assure method thursdayHerdheaven
 
Un mémo pour identifier la nature des difficultés et leurs degrés de gravité
Un mémo pour identifier la nature des difficultés et leurs degrés de gravitéUn mémo pour identifier la nature des difficultés et leurs degrés de gravité
Un mémo pour identifier la nature des difficultés et leurs degrés de gravitéChambres d'agriculture de Bretagne
 
Bitclub spanish
Bitclub spanishBitclub spanish
Bitclub spanishBro Olio
 
20150528ppyongsanlocalhostproposal01 150604101009-lva1-app6891
20150528ppyongsanlocalhostproposal01 150604101009-lva1-app689120150528ppyongsanlocalhostproposal01 150604101009-lva1-app6891
20150528ppyongsanlocalhostproposal01 150604101009-lva1-app6891Jescia Aquilizan
 
Alfabetus2
Alfabetus2Alfabetus2
Alfabetus2Ina Dana
 
Yahoo! Connected TV - Developer Event - Device Communication
Yahoo! Connected TV - Developer Event - Device CommunicationYahoo! Connected TV - Developer Event - Device Communication
Yahoo! Connected TV - Developer Event - Device CommunicationYahooConnectedTV
 
Colchicina en Metafase por George Vaca-Guerrero
Colchicina en Metafase por George Vaca-GuerreroColchicina en Metafase por George Vaca-Guerrero
Colchicina en Metafase por George Vaca-Guerrerog_vaca-guerrero
 

Viewers also liked (13)

Portes ouvertes Innov'Action 2016 Morbihan - CUMA de Questembert
Portes ouvertes Innov'Action 2016 Morbihan - CUMA de QuestembertPortes ouvertes Innov'Action 2016 Morbihan - CUMA de Questembert
Portes ouvertes Innov'Action 2016 Morbihan - CUMA de Questembert
 
Ci 350 assure method thursday
Ci 350 assure method thursdayCi 350 assure method thursday
Ci 350 assure method thursday
 
Degree certificate
Degree certificateDegree certificate
Degree certificate
 
Texto movs. amparo ecija. el espectador minimalista
Texto movs. amparo ecija. el espectador minimalistaTexto movs. amparo ecija. el espectador minimalista
Texto movs. amparo ecija. el espectador minimalista
 
Eversports Reference.PDF
Eversports Reference.PDFEversports Reference.PDF
Eversports Reference.PDF
 
AddictedPowerPoint (2)
AddictedPowerPoint (2)AddictedPowerPoint (2)
AddictedPowerPoint (2)
 
Un mémo pour identifier la nature des difficultés et leurs degrés de gravité
Un mémo pour identifier la nature des difficultés et leurs degrés de gravitéUn mémo pour identifier la nature des difficultés et leurs degrés de gravité
Un mémo pour identifier la nature des difficultés et leurs degrés de gravité
 
Bitclub spanish
Bitclub spanishBitclub spanish
Bitclub spanish
 
20150528ppyongsanlocalhostproposal01 150604101009-lva1-app6891
20150528ppyongsanlocalhostproposal01 150604101009-lva1-app689120150528ppyongsanlocalhostproposal01 150604101009-lva1-app6891
20150528ppyongsanlocalhostproposal01 150604101009-lva1-app6891
 
Alfabetus2
Alfabetus2Alfabetus2
Alfabetus2
 
Yahoo! Connected TV - Developer Event - Device Communication
Yahoo! Connected TV - Developer Event - Device CommunicationYahoo! Connected TV - Developer Event - Device Communication
Yahoo! Connected TV - Developer Event - Device Communication
 
Dialnet un enfoquepedagogicodeladanza-3237201
Dialnet un enfoquepedagogicodeladanza-3237201Dialnet un enfoquepedagogicodeladanza-3237201
Dialnet un enfoquepedagogicodeladanza-3237201
 
Colchicina en Metafase por George Vaca-Guerrero
Colchicina en Metafase por George Vaca-GuerreroColchicina en Metafase por George Vaca-Guerrero
Colchicina en Metafase por George Vaca-Guerrero
 

Similar to ProGuard Optimizer and Obfuscator in the Android SDK

Droidcon2013 pro guard, optimizer and obfuscator in the android sdk_eric lafo...
Droidcon2013 pro guard, optimizer and obfuscator in the android sdk_eric lafo...Droidcon2013 pro guard, optimizer and obfuscator in the android sdk_eric lafo...
Droidcon2013 pro guard, optimizer and obfuscator in the android sdk_eric lafo...Droidcon Berlin
 
Compiler Optimization Presentation
Compiler Optimization PresentationCompiler Optimization Presentation
Compiler Optimization Presentation19magnet
 
Code Generation in PHP - PHPConf 2015
Code Generation in PHP - PHPConf 2015Code Generation in PHP - PHPConf 2015
Code Generation in PHP - PHPConf 2015Lin Yo-An
 
JavaScript Functions
JavaScript FunctionsJavaScript Functions
JavaScript FunctionsBrian Moschel
 
The following is the (incomplete) header file for the class Fracti.pdf
The following is the (incomplete) header file for the class Fracti.pdfThe following is the (incomplete) header file for the class Fracti.pdf
The following is the (incomplete) header file for the class Fracti.pdf4babies2010
 
1 arithmetic
1 arithmetic1 arithmetic
1 arithmeticfyjordan9
 
How to practice functional programming in react
How to practice functional programming in reactHow to practice functional programming in react
How to practice functional programming in reactNetta Bondy
 
Facts about multithreading that'll keep you up at night - Guy Bar on, Vonage
Facts about multithreading that'll keep you up at night - Guy Bar on, VonageFacts about multithreading that'll keep you up at night - Guy Bar on, Vonage
Facts about multithreading that'll keep you up at night - Guy Bar on, VonageCodemotion Tel Aviv
 
Write a program that works with fractions. You are first to implemen.pdf
Write a program that works with fractions. You are first to implemen.pdfWrite a program that works with fractions. You are first to implemen.pdf
Write a program that works with fractions. You are first to implemen.pdfleventhalbrad49439
 
From clever code to better code
From clever code to better codeFrom clever code to better code
From clever code to better codeDror Helper
 
DeVry GSP 115 All Assignments latest
DeVry GSP 115 All Assignments latestDeVry GSP 115 All Assignments latest
DeVry GSP 115 All Assignments latestAtifkhilji
 
The mighty js_function
The mighty js_functionThe mighty js_function
The mighty js_functiontimotheeg
 
Kinect v2 Introduction and Tutorial
Kinect v2 Introduction and TutorialKinect v2 Introduction and Tutorial
Kinect v2 Introduction and TutorialTsukasa Sugiura
 
2.1 ### uVision Project, (C) Keil Software .docx
2.1   ### uVision Project, (C) Keil Software    .docx2.1   ### uVision Project, (C) Keil Software    .docx
2.1 ### uVision Project, (C) Keil Software .docxtarifarmarie
 
Assignment #2.classpathAssignment #2.project Assig.docx
Assignment #2.classpathAssignment #2.project  Assig.docxAssignment #2.classpathAssignment #2.project  Assig.docx
Assignment #2.classpathAssignment #2.project Assig.docxfredharris32
 
C++ Question on References and Function Overloading
C++ Question on References and Function OverloadingC++ Question on References and Function Overloading
C++ Question on References and Function Overloadingmohamed sikander
 

Similar to ProGuard Optimizer and Obfuscator in the Android SDK (20)

Droidcon2013 pro guard, optimizer and obfuscator in the android sdk_eric lafo...
Droidcon2013 pro guard, optimizer and obfuscator in the android sdk_eric lafo...Droidcon2013 pro guard, optimizer and obfuscator in the android sdk_eric lafo...
Droidcon2013 pro guard, optimizer and obfuscator in the android sdk_eric lafo...
 
Compiler Optimization Presentation
Compiler Optimization PresentationCompiler Optimization Presentation
Compiler Optimization Presentation
 
Code Generation in PHP - PHPConf 2015
Code Generation in PHP - PHPConf 2015Code Generation in PHP - PHPConf 2015
Code Generation in PHP - PHPConf 2015
 
JavaScript Functions
JavaScript FunctionsJavaScript Functions
JavaScript Functions
 
The following is the (incomplete) header file for the class Fracti.pdf
The following is the (incomplete) header file for the class Fracti.pdfThe following is the (incomplete) header file for the class Fracti.pdf
The following is the (incomplete) header file for the class Fracti.pdf
 
1 arithmetic
1 arithmetic1 arithmetic
1 arithmetic
 
How to practice functional programming in react
How to practice functional programming in reactHow to practice functional programming in react
How to practice functional programming in react
 
Facts about multithreading that'll keep you up at night - Guy Bar on, Vonage
Facts about multithreading that'll keep you up at night - Guy Bar on, VonageFacts about multithreading that'll keep you up at night - Guy Bar on, Vonage
Facts about multithreading that'll keep you up at night - Guy Bar on, Vonage
 
Write a program that works with fractions. You are first to implemen.pdf
Write a program that works with fractions. You are first to implemen.pdfWrite a program that works with fractions. You are first to implemen.pdf
Write a program that works with fractions. You are first to implemen.pdf
 
From clever code to better code
From clever code to better codeFrom clever code to better code
From clever code to better code
 
Rust Intro
Rust IntroRust Intro
Rust Intro
 
DeVry GSP 115 All Assignments latest
DeVry GSP 115 All Assignments latestDeVry GSP 115 All Assignments latest
DeVry GSP 115 All Assignments latest
 
The mighty js_function
The mighty js_functionThe mighty js_function
The mighty js_function
 
Kinect v2 Introduction and Tutorial
Kinect v2 Introduction and TutorialKinect v2 Introduction and Tutorial
Kinect v2 Introduction and Tutorial
 
2.1 ### uVision Project, (C) Keil Software .docx
2.1   ### uVision Project, (C) Keil Software    .docx2.1   ### uVision Project, (C) Keil Software    .docx
2.1 ### uVision Project, (C) Keil Software .docx
 
Assignment #2.classpathAssignment #2.project Assig.docx
Assignment #2.classpathAssignment #2.project  Assig.docxAssignment #2.classpathAssignment #2.project  Assig.docx
Assignment #2.classpathAssignment #2.project Assig.docx
 
Pruning your code
Pruning your codePruning your code
Pruning your code
 
C++ aptitude
C++ aptitudeC++ aptitude
C++ aptitude
 
C++ Question on References and Function Overloading
C++ Question on References and Function OverloadingC++ Question on References and Function Overloading
C++ Question on References and Function Overloading
 
ES6
ES6ES6
ES6
 

Recently uploaded

The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdfThe Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdfkalichargn70th171
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...MyIntelliSource, Inc.
 
why an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfwhy an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfjoe51371421
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVshikhaohhpro
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...ICS
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)OPEN KNOWLEDGE GmbH
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfkalichargn70th171
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software DevelopersVinodh Ram
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comFatema Valibhai
 
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...Christina Lin
 
What is Binary Language? Computer Number Systems
What is Binary Language?  Computer Number SystemsWhat is Binary Language?  Computer Number Systems
What is Binary Language? Computer Number SystemsJheuzeDellosa
 
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...stazi3110
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantAxelRicardoTrocheRiq
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsAlberto González Trastoy
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio, Inc.
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdfWave PLM
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...MyIntelliSource, Inc.
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxbodapatigopi8531
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityNeo4j
 

Recently uploaded (20)

The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdfThe Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
 
why an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfwhy an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdf
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTV
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software Developers
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.com
 
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
 
What is Binary Language? Computer Number Systems
What is Binary Language?  Computer Number SystemsWhat is Binary Language?  Computer Number Systems
What is Binary Language? Computer Number Systems
 
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service Consultant
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
Exploring iOS App Development: Simplifying the Process
Exploring iOS App Development: Simplifying the ProcessExploring iOS App Development: Simplifying the Process
Exploring iOS App Development: Simplifying the Process
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptx
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered Sustainability
 

ProGuard Optimizer and Obfuscator in the Android SDK

  • 1. ProGuard Optimizer and Obfuscator in the Android SDK Eric Lafortune Developer of ProGuard Technical director at Saikoa
  • 2. Topics ProGuard – Techniques – Results More application protection – Goals – Attackers – Types of attacks – Protection
  • 4. ProGuard history Java 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
  • 6. ProGuard in Android builds Application Java bytecode ProGuard Libraries Java bytecode Processed Java bytecode Dex Dalvik bytecode Javac Application Java source Libraries Java bytecode XML resources Assets Assets Compiled XML resourcesAapt
  • 7. Why use ProGuard? ● Application size ● Performance ● Remove logging, debugging, testing code ● Protection
  • 8. Application size classes.dex size .apk size Without ProGuard With ProGuard Reduction ApiDemos 716 K 482 K 33 % 2.6 M 2.5 M 4 % GoogleIO App 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]
  • 9. 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]
  • 10. Battery life Extreme example: “5 x better battery life, by removing verbose logging code in a background service” (but don't count on it)
  • 11. Results ● Size reduction: – Code (classes.dex): 20 … 90% – Application (.apk): 5 ... 70% ● Performance improvements: 0 … 20%
  • 12. 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
  • 13. 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
  • 14. 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.JSONArray Warning: 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.Logger Warning: 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.Logger Warning: twitter4j.internal.logging.SLF4JLoggerFactory: can't find referenced class org.slf4j.LoggerFactory ... Tip
  • 15. 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
  • 16. Shrinking Also called treeshaking, minimizing, shrouding
  • 18. 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 …
  • 19. 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
  • 20. Optimization At the bytecode instruction level: ● Dead code elimination ● Constant propagation ● Method inlining ● Class merging ● Remove logging code ● Peephole optimizations ● Devirtualization ● ...
  • 21. Optimization example int 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); } }
  • 22. Optimization example int 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); }
  • 23. Optimization example int 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
  • 24. Optimization example int 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; }
  • 25. Optimization example int 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;
  • 26. Optimization: enum int 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
  • 27. Optimization: enum int 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
  • 28. Optimization: enum int 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; } }
  • 29. Optimization: enum int 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; } }
  • 30. Optimization: enum int 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; } }
  • 31. Optimization: enum int 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;
  • 32. How to enable optimization? Ant and Eclipse: project.properties # To enable ProGuard to shrink and obfuscate your code, uncomment this proguard.config= ${sdk.dir}/tools/proguard/proguard-android-optimize.txt: proguard-project.txt # To enable ProGuard to shrink and obfuscate your code, uncomment this proguard.config= ${sdk.dir}/tools/proguard/proguard-android-optimize.txt: proguard-project.txt Tip
  • 33. 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
  • 34. 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
  • 35. Obfuscation Traditional name obfuscation: ● Rename identifiers: class/field/method names ● Remove debug information: line numbers, local variable names,...
  • 36. Obfuscation example public 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; } }
  • 37. Obfuscation example public 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; } }
  • 39. What about ART? The new (experimental) Android RunTime Application Java bytecode ProGuard Libraries Java bytecode Processed Java bytecode Dex Dalvik bytecode Dex2oat Native code Development Device
  • 40. 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”); } }
  • 41. 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”); } }
  • 46. Time
  • 49. Static analysis ● Disassemblers: dexdump, baksmali ● Decompilers: dex2jar + jad, JD-GUI, JEB,... ● Resources: aapt, apktool,...
  • 53. 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=”));
  • 54. 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!” });
  • 56. libutil.so libutil.so Native code Java Native Interface classes.dex libutil.so classes.dex
  • 57. 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);
  • 58. 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; }
  • 59. 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();
  • 61. 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
  • 62. DexGuard ● Specialized for Android ● Code and data ● Layers of protection ● Recommended techniques ● Low-level techniques ● Transparent Tip Code Resources Assets Signatures
  • 63. ProGuard - DexGuard Open source Generic Shrinker Optimizer Obfuscator For Java bytecode Closed source Specialized Shrinker Optimizer Obfuscator Protector For Android Compatible
  • 64. ProGuard guide – Android SDK developer.android.comdeveloper.android.com