Some security issues in Android development: Activity

Some security issues in Android development: Activity

1. The activities used within this app must be set to private

Activities that are not intended to be made public must be set to private to prevent illegal calls

  1. <activity
  2. android:name= ".PrivateActivity"  
  3. android:label= "@string/app_name"  
  4. android:exported= "false" />
  5.  
  6. <activity
  7. android:name= ".PrivateActivity"  
  8. android:label= "@string/app_name"  
  9. android:exported= "false" />

At the same time, it is important to note that non-public Activities cannot set intent-filters

Because, if there is another app with the same intent-filter on the same machine, calling the Activity's intent will wake up the Android selection screen, allowing you to choose which app to use to accept the intent. This will actually bypass the non-public settings.

2. Don’t specify taskAffinity

All activities in Android are managed by tasks. Simply put, tasks are a stack data structure with a first-in, last-out order.

Generally speaking, if you don't specify which task it belongs to, all Activities in the same app will exist in one task, and the name of the task is the packageName of the app.

Because there will not be two apps with the same packageName in the same Android device, the Activity can be protected from attack.

But if you specify taskAffinity, such as the following

  1. [html]
  2. <application android:icon= "@drawable/icon" android:label= "@string/app_name" >
  3. <activity android:name= ".Activity1"  
  4. android:taskAffinity= "com.winuxxan.task"  
  5. android:label= "@string/app_name" >
  6. </activity>
  7. <activity android:name= ".Activity2" >
  8. <intent-filter>
  9. <action android:name= "android.intent.action.MAIN" />
  10. <category android:name= "android.intent.category.LAUNCHER" />
  11. </intent-filter>
  12. </activity>
  13. </application>
  14.  
  15. <application android:icon= "@drawable/icon" android:label= "@string/app_name" >
  16. <activity android:name= ".Activity1"  
  17. android:taskAffinity= "com.winuxxan.task"  
  18. android:label= "@string/app_name" >
  19. </activity>
  20. <activity android:name= ".Activity2" >
  21. <intent-filter>
  22. <action android:name= "android.intent.action.MAIN" />
  23. <category android:name= "android.intent.category.LAUNCHER" />
  24. </intent-filter>
  25. </activity>
  26. </application>

At this point, if the malware's Activity is also declared as the same taskAffinity, then its Activity will be started in your task and will have a chance to get your intent.

3. Do not specify LaunchMode (default standard mode)

The LaunchMode of Activity in Android is divided into the following four types

Standard: The Activity opened in this way will not be treated as the rootActivity. A new Activity instance will be generated and will be in the same task as the opener.

singleTop: Same as standard, except that if the first Activity in the current task is this Activity, no new instance will be generated.

singleTask: The system creates a new task (if the application is not started) and a new instance of the activity at the root of the new task. Then, if the activity instance already exists in a separate task, the system calls the onNewIntent() method of the existing activity instead of creating a new instance. Only one activity instance exists at the same time.

singleInstance: Similar to singleTask, except that the system will not let other activities run in all held task instances. This activity is independent and is the only member of the task. Any other activities running this activity will open an independent task.

All intents sent to the root Activity will leave a record in Android. So generally speaking, it is forbidden to use singleTask or singleInstance to start the screen.

However, even if you use the standard mode to open the screen, there may be problems. For example, if the caller's Activity is opened in singleInstance mode, that is, the called Activity is opened in standard mode, because the caller's Activitytask cannot have other tasks, Android will be forced to generate a new task and put the callee into it. In the end, the callee becomes the rootActivity.

The procedure is as follows:

  1. AndroidManifest.xml
  2.  
  3. [html]
  4. <?xml version= "1.0" encoding= "utf-8" ?>
  5. <manifest xmlns:android= "http://schemas.android.com/apk/res/android"  
  6. package = "org.jssec.android.activity.privateactivity"  
  7. android:versionCode= "1"  
  8. android:versionName= "1.0" >
  9. <uses-sdk android:minSdkVersion= "8" />
  10. <application
  11. android:icon= "@drawable/ic_launcher"  
  12. android:label= "@string/app_name" >
  13. <!—The root Activity is started in "singleInstance" mode -->
  14. <!—Do not set taskAffinity-->
  15. <activity
  16. android:name= ".PrivateUserActivity"  
  17. android:label= "@string/app_name"  
  18. android:launchMode= "singleInstance" >
  19. <intent-filter>
  20. <action android:name= "android.intent.action.MAIN" />
  21. <category android:name= "android.intent.category.LAUNCHER" />
  22. </intent-filter>
  23. </activity>
  24. <!-- Non-public Activity -->
  25. <!—Startup mode is "standard" -->
  26. <!—Do not set taskAffinity-->
  27. <activity
  28. android:name= ".PrivateActivity"  
  29. android:label= "@string/app_name"  
  30. android:exported= "false" />
  31. </application>
  32. </manifest>
  33.  
  34. <?xml version= "1.0" encoding= "utf-8" ?>
  35. <manifest xmlns:android= "http://schemas.android.com/apk/res/android"  
  36. package = "org.jssec.android.activity.privateactivity"  
  37. android:versionCode= "1"  
  38. android:versionName= "1.0" >
  39. <uses-sdk android:minSdkVersion= "8" />
  40. <application
  41. android:icon= "@drawable/ic_launcher"  
  42. android:label= "@string/app_name" >
  43. <!—The root Activity is started in "singleInstance" mode -->
  44. <!—Do not set taskAffinity-->
  45. <activity
  46. android:name= ".PrivateUserActivity"  
  47. android:label= "@string/app_name"  
  48. android:launchMode= "singleInstance" >
  49. <intent-filter>
  50. <action android:name= "android.intent.action.MAIN" />
  51. <category android:name= "android.intent.category.LAUNCHER" />
  52. </intent-filter>
  53. </activity>
  54. <!-- Non-public Activity -->
  55. <!—Startup mode is "standard" -->
  56. <!—Do not set taskAffinity-->
  57. <activity
  58. android:name= ".PrivateActivity"  
  59. android:label= "@string/app_name"  
  60. android:exported= "false" />
  61. </application>
  62. </manifest>

The code of the non-public Activity is as follows:

  1. [java]
  2. package org.jssec.android.activity.privateactivity;
  3. import android.app.Activity;
  4. import android.content.Intent;
  5. import android.os.Bundle;
  6. import android.view.View;
  7. import android.widget.Toast;
  8. public   class PrivateActivity extends Activity {
  9. @Override  
  10. public   void onCreate(Bundle savedInstanceState) {
  11. super .onCreate(savedInstanceState);
  12. setContentView(R.layout.private_activity);
  13. String param = getIntent().getStringExtra( "PARAM" );
  14. Toast.makeText( this , String.format( ""%s" is obtained." , param),
  15. Toast.LENGTH_LONG).show();
  16. }
  17.  
  18. public   void onReturnResultClick(View view) {
  19. Intent intent = new Intent();
  20. intent.putExtra( "RESULT" , confidential data");
  21. setResult(RESULT_OK, intent);
  22. finish();
  23. }
  24. }
  25.  
  26. package org.jssec.android.activity.privateactivity;
  27. import android.app.Activity;
  28. import android.content.Intent;
  29. import android.os.Bundle;
  30. import android.view.View;
  31. import android.widget.Toast;
  32. public   class PrivateActivity extends Activity {
  33. @Override  
  34. public   void onCreate(Bundle savedInstanceState) {
  35. super .onCreate(savedInstanceState);
  36. setContentView(R.layout.private_activity);
  37. String param = getIntent().getStringExtra( "PARAM" );
  38. Toast.makeText( this , String.format( ""%s" is obtained." , param),
  39. Toast.LENGTH_LONG).show();
  40. }
  41.  
  42. public   void onReturnResultClick(View view) {
  43. Intent intent = new Intent();
  44. intent.putExtra( "RESULT" , confidential data");
  45. setResult(RESULT_OK, intent);
  46. finish();
  47. }
  48. }

The caller of a non-public Activity opens it in standard mode

  1. [java]
  2. package org.jssec.android.activity.privateactivity;
  3. import android.app.Activity;
  4. import android.content.Intent;
  5. import android.os.Bundle;
  6. import android.view.View;
  7. import android.widget.Toast;
  8. public   class PrivateUserActivity extends Activity {
  9. private   static   final   int REQUEST_CODE = 1 ;
  10.  
  11. @Override  
  12. public   void onCreate(Bundle savedInstanceState) {
  13. super .onCreate(savedInstanceState);
  14. setContentView(R.layout.user_activity);
  15. }
  16.  
  17. public   void onUseActivityClick(View view) {
  18. // Start a non-public Activity in standard mode  
  19. Intent intent = new Intent();
  20. intent.setClass( this , PrivateActivity. class );
  21. intent.putExtra( "PARAM" , "Confidential data" );
  22. startActivityForResult(intent, REQUEST_CODE);
  23. }
  24.  
  25. @Override  
  26. public   void onActivityResult( int requestCode, int resultCode,
  27. Intent data) {
  28. super .onActivityResult(requestCode, resultCode, data);
  29. if (resultCode != RESULT_OK)
  30. return ;
  31. switch (requestCode) {
  32. case REQUEST_CODE:
  33. String result = data.getStringExtra( "RESULT" );
  34. break ;
  35. }
  36. }
  37. }
  38.  
  39. package org.jssec.android.activity.privateactivity;
  40. import android.app.Activity;
  41. import android.content.Intent;
  42. import android.os.Bundle;
  43. import android.view.View;
  44. import android.widget.Toast;
  45. public   class PrivateUserActivity extends Activity {
  46. private   static   final   int REQUEST_CODE = 1 ;
  47.  
  48. @Override  
  49. public   void onCreate(Bundle savedInstanceState) {
  50. super .onCreate(savedInstanceState);
  51. setContentView(R.layout.user_activity);
  52. }
  53.  
  54. public   void onUseActivityClick(View view) {
  55. // Start a non-public Activity in standard mode  
  56. Intent intent = new Intent();
  57. intent.setClass( this , PrivateActivity. class );
  58. intent.putExtra( "PARAM" , "Confidential data" );
  59. startActivityForResult(intent, REQUEST_CODE);
  60. }
  61.  
  62. @Override  
  63. public   void onActivityResult( int requestCode, int resultCode,
  64. Intent data) {
  65. super .onActivityResult(requestCode, resultCode, data);
  66. if (resultCode != RESULT_OK)
  67. return ;
  68. switch (requestCode) {
  69. case REQUEST_CODE:
  70. String result = data.getStringExtra( "RESULT" );
  71. break ;
  72. }
  73. }
  74. }

 

4. Do not set the intent sent to the Activity to FLAG_ACTIVITY_NEW_TASK

Even if the lauchMode of the above Activity is set perfectly, you can still specify the opening mode when opening the intent.

For example, if the FLAG_ACTIVITY_NEW_TASK mode is specified in the intent, if the activity does not exist, a new task will be created. If FLAG_ACTIVITY_MULTIPLE_TASK + FLAG_ACTIVITY_NEW_TASK are set at the same time, a new task will be generated no matter what, the activity will become the rootActiviy, and the intent will be saved as a resume

 

5. Encryption of data in Intent

The data transmission in Activity relies on intent, which is very easy to be attacked. Therefore, even if the data is transmitted within the same app, it is best to encrypt it. There are many encryption algorithms.

6. Clear ActivityName to send Intent

Clearly sending the Intent by Activity can prevent it from being intercepted by malware.

Sending within the same app

  1. [java]
  2. Intent intent = new Intent( this , PictureActivity. class );
  3. intent.putExtra( "BARCODE" , barcode);
  4. startActivity(intent);
  5.  
  6. Intent intent = new Intent( this , PictureActivity. class );
  7. intent.putExtra( "BARCODE" , barcode);
  8. startActivity(intent);
  9.  
  10.  
  11. Sending within different apps
  12.  
  13. [java]
  14. Intent intent = new Intent();
  15. intent.setClassName(
  16. "org.jssec.android.activity.publicactivity" ,
  17. "org.jssec.android.activity.publicactivity.PublicActivity" );
  18. startActivity(intent);
  19.  
  20. Intent intent = new Intent();
  21. intent.setClassName(
  22. "org.jssec.android.activity.publicactivity" ,
  23. "org.jssec.android.activity.publicactivity.PublicActivity" );
  24. startActivity(intent);

But, be careful!

Not all problems can be avoided by specifying packageName and ActivityName.

If a malware deliberately creates the same packageName and ActivityName as the target you are sending to, the intent will be intercepted.

7. When accepting intents across apps, make sure the other party is identified

When receiving an intent from another app, you need to be able to determine the identity of the other party.

A good way is to compare the hashcode of the other party's app.

Currently, the premise is that the caller must use startActivityForResult(), because only this method can the callee get the caller's packageName

The code is as follows:

The called Activity

  1. [java]
  2. package org.jssec.android.activity.exclusiveactivity;
  3. import org.jssec.android.shared.PkgCertWhitelists;
  4. import org.jssec.android.shared.Utils;
  5. import android.app.Activity;
  6. import android.content.Context;
  7. import android.content.Intent;
  8. import android.os.Bundle;
  9. import android.view.View;
  10. import android.widget.Toast;
  11. public   class ExclusiveActivity extends Activity {
  12. // hashcode whitelist  
  13. private   static PkgCertWhitelists sWhitelists = null ;
  14.  
  15. private   static   void buildWhitelists(Context context) {
  16. boolean isdebug = Utils.isDebuggable(context);
  17. sWhitelists = new PkgCertWhitelists();
  18. sWhitelists
  19. .add( "org.jssec.android.activity.exclusiveuser" , isdebug ?
  20. "0EFB7236 328348A9 89718BAD DF57F544 D5CCB4AE B9DB34BC 1E29DD26 F77C8255"  
  21. :
  22. "1F039BB5 7861C27A 3916C778 8E78CE00 690B3974 3EB8259F E2627B8D 4C0EC35A" );
  23. }
  24.  
  25. private   static   boolean checkPartner(Context context, String pkgname) {
  26. if (sWhitelists == null )
  27. buildWhitelists(context);
  28. return sWhitelists.test(context, pkgname);
  29. }
  30.  
  31. @Override  
  32. public   void onCreate(Bundle savedInstanceState) {
  33. super .onCreate(savedInstanceState);
  34. setContentView(R.layout.main);
  35. // check whitelist  
  36. if (!checkPartner( this , getCallingPackage())) {
  37. Toast.makeText( this , "Not in the whitelist." , Toast.LENGTH_LONG).show();
  38. finish();
  39. return ;
  40. }
  41. }
  42.  
  43. public   void onReturnResultClick(View view) {
  44. Intent intent = new Intent();
  45. intent.putExtra( "RESULT" , "confidential data" );
  46. setResult(RESULT_OK, intent);
  47. finish();
  48. }
  49. }
  50.  
  51. package org.jssec.android.activity.exclusiveactivity;
  52. import org.jssec.android.shared.PkgCertWhitelists;
  53. import org.jssec.android.shared.Utils;
  54. import android.app.Activity;
  55. import android.content.Context;
  56. import android.content.Intent;
  57. import android.os.Bundle;
  58. import android.view.View;
  59. import android.widget.Toast;
  60. public   class ExclusiveActivity extends Activity {
  61. // hashcode whitelist  
  62. private   static PkgCertWhitelists sWhitelists = null ;
  63.  
  64. private   static   void buildWhitelists(Context context) {
  65. boolean isdebug = Utils.isDebuggable(context);
  66. sWhitelists = new PkgCertWhitelists();
  67. sWhitelists
  68. .add( "org.jssec.android.activity.exclusiveuser" , isdebug ?
  69. "0EFB7236 328348A9 89718BAD DF57F544 D5CCB4AE B9DB34BC 1E29DD26 F77C8255"  
  70. :
  71. "1F039BB5 7861C27A 3916C778 8E78CE00 690B3974 3EB8259F E2627B8D 4C0EC35A" );
  72. }
  73.  
  74. private   static   boolean checkPartner(Context context, String pkgname) {
  75. if (sWhitelists == null )
  76. buildWhitelists(context);
  77. return sWhitelists.test(context, pkgname);
  78. }
  79.  
  80. @Override  
  81. public   void onCreate(Bundle savedInstanceState) {
  82. super .onCreate(savedInstanceState);
  83. setContentView(R.layout.main);
  84. // check whitelist  
  85. if (!checkPartner( this , getCallingPackage())) {
  86. Toast.makeText( this , "Not in the whitelist." , Toast.LENGTH_LONG).show();
  87. finish();
  88. return ;
  89. }
  90. }
  91.  
  92. public   void onReturnResultClick(View view) {
  93. Intent intent = new Intent();
  94. intent.putExtra( "RESULT" , "confidential data" );
  95. setResult(RESULT_OK, intent);
  96. finish();
  97. }
  98. } [java]
  99.  
  100.  
  101. PkgCertWhitelists.java
  102. [java]
  103. package org.jssec.android.shared;
  104. import java.util.HashMap;
  105. import java.util.Map;
  106. import android.content.Context;
  107. public   class PkgCertWhitelists {
  108. private Map<String, String> mWhitelists = new HashMap<String, String>();
  109.  
  110. public   boolean add(String pkgname, String sha256) {
  111. if (pkgname == null )
  112. return   false ;
  113. if (sha256 == null )
  114. return   false ;
  115. sha256 = sha256.replaceAll( " " , "" );
  116. if (sha256.length() != 64 )
  117. return   false ;
  118. sha256 = sha256.toUpperCase();
  119. if (sha256.replaceAll( "[0-9A-F]+" , "" ).length() != 0 )
  120. return   false ;
  121. mWhitelists.put(pkgname, sha256);
  122. return   true ;
  123. }
  124.  
  125. public   boolean test(Context ctx, String pkgname) {
  126. String correctHash = mWhitelists.get(pkgname);
  127. return PkgCert.test(ctx, pkgname, correctHash);
  128. }
  129. }
  130.  
  131. package org.jssec.android.shared;
  132. import java.util.HashMap;
  133. import java.util.Map;
  134. import android.content.Context;
  135. public   class PkgCertWhitelists {
  136. private Map<String, String> mWhitelists = new HashMap<String, String>();
  137.  
  138. public   boolean add(String pkgname, String sha256) {
  139. if (pkgname == null )
  140. return   false ;
  141. if (sha256 == null )
  142. return   false ;
  143. sha256 = sha256.replaceAll( " " , "" );
  144. if (sha256.length() != 64 )
  145. return   false ;
  146. sha256 = sha256.toUpperCase();
  147. if (sha256.replaceAll( "[0-9A-F]+" , "" ).length() != 0 )
  148. return   false ;
  149. mWhitelists.put(pkgname, sha256);
  150. return   true ;
  151. }
  152.  
  153. public   boolean test(Context ctx, String pkgname) {
  154. String correctHash = mWhitelists.get(pkgname);
  155. return PkgCert.test(ctx, pkgname, correctHash);
  156. }
  157. }
  158. PkgCert.java
  159. [java]
  160.  
  161. package org.jssec.android.shared;
  162. import java.security.MessageDigest;
  163. import java.security.NoSuchAlgorithmException;
  164. import android.content.Context;
  165. import android.content.pm.PackageInfo;
  166. import android.content.pm.PackageManager;
  167. import android.content.pm.PackageManager.NameNotFoundException;
  168. import android.content.pm.Signature;
  169. public   class PkgCert {
  170. public   static   boolean test(Context ctx, String pkgname,
  171. String correctHash) {
  172. if (correctHash == null )
  173. return   false ;
  174. correctHash = correctHash.replaceAll( " " , "" );
  175. return correctHash.equals(hash(ctx, pkgname));
  176. }
  177.  
  178. public   static String hash(Context ctx, String pkgname) {
  179. if (pkgname == null )
  180. return   null ;
  181. try {
  182. PackageManager pm = ctx.getPackageManager();
  183. PackageInfo pkginfo = pm.getPackageInfo(pkgname,
  184. PackageManager.GET_SIGNATURES);
  185. if (pkginfo.signatures.length != 1 )
  186. return   null ;
  187. Signature sig = pkginfo.signatures[ 0 ];
  188. byte [] cert = sig.toByteArray();
  189. byte [] sha256 = computeSha256(cert);
  190. return byte2hex(sha256);
  191. } catch (NameNotFoundException e) {
  192. return   null ;
  193. }
  194. }
  195.  
  196. private   static   byte [] computeSha256( byte [] data) {
  197. try {
  198. return MessageDigest.getInstance( "SHA-256" ).digest(data);
  199. } catch (NoSuchAlgorithmException e) {
  200. return   null ;
  201. }
  202. }
  203.  
  204. private   static String byte2hex( byte [] data) {
  205. if (data == null )
  206. return   null ;
  207. final StringBuilder hexadecimal = new StringBuilder();
  208. for ( final   byte b : data) {
  209. hexadecimal.append(String.format( "%02X" , b));
  210. }
  211. return hexadecimal.toString();
  212. }
  213. }
  214.  
  215.  
  216. package org.jssec.android.shared;
  217. import java.security.MessageDigest;
  218. import java.security.NoSuchAlgorithmException;
  219. import android.content.Context;
  220. import android.content.pm.PackageInfo;
  221. import android.content.pm.PackageManager;
  222. import android.content.pm.PackageManager.NameNotFoundException;
  223. import android.content.pm.Signature;
  224. public   class PkgCert {
  225. public   static   boolean test(Context ctx, String pkgname,
  226. String correctHash) {
  227. if (correctHash == null )
  228. return   false ;
  229. correctHash = correctHash.replaceAll( " " , "" );
  230. return correctHash.equals(hash(ctx, pkgname));
  231. }
  232.  
  233. public   static String hash(Context ctx, String pkgname) {
  234. if (pkgname == null )
  235. return   null ;
  236. try {
  237. PackageManager pm = ctx.getPackageManager();
  238. PackageInfo pkginfo = pm.getPackageInfo(pkgname,
  239. PackageManager.GET_SIGNATURES);
  240. if (pkginfo.signatures.length != 1 )
  241. return   null ;
  242. Signature sig = pkginfo.signatures[ 0 ];
  243. byte [] cert = sig.toByteArray();
  244. byte [] sha256 = computeSha256(cert);
  245. return byte2hex(sha256);
  246. } catch (NameNotFoundException e) {
  247. return   null ;
  248. }
  249. }
  250.  
  251. private   static   byte [] computeSha256( byte [] data) {
  252. try {
  253. return MessageDigest.getInstance( "SHA-256" ).digest(data);
  254. } catch (NoSuchAlgorithmException e) {
  255. return   null ;
  256. }
  257. }
  258.  
  259. private   static String byte2hex( byte [] data) {
  260. if (data == null )
  261. return   null ;
  262. final StringBuilder hexadecimal = new StringBuilder();
  263. for ( final   byte b : data) {
  264. hexadecimal.append(String.format( "%02X" , b));
  265. }
  266. return hexadecimal.toString();
  267. }
  268. }

8. All intents in the root Activity can be shared by all apps

All apps can retrieve the intents received by all root activities in all tasks on this phone as follows:

  1. AndroidManifest.xml
  2.  
  3. [html]
  4. <manifest xmlns:android= "http://schemas.android.com/apk/res/android"  
  5. package = "org.jssec.android.intent.maliciousactivity"  
  6. android:versionCode= "1"  
  7. android:versionName= "1.0" >
  8.  
  9. <uses-sdk
  10. android:minSdkVersion= "8"  
  11. android:targetSdkVersion= "15" />
  12.  
  13. <application
  14. android:icon= "@drawable/ic_launcher"  
  15. android:label= "@string/app_name"  
  16. android:theme= "@style/AppTheme" >
  17. <activity
  18. android:name= ".MaliciousActivity"  
  19. android:label= "@string/title_activity_main" >
  20. <intent-filter>
  21. <action android:name= "android.intent.action.MAIN" />
  22.  
  23. <category android:name= "android.intent.category.LAUNCHER" />
  24. </intent-filter>
  25. </activity>
  26. </application>
  27.  
  28. <uses-permission android:name= "android.permission.GET_TASKS" />
  29.  
  30. </manifest>
  31.  
  32. <manifest xmlns:android= "http://schemas.android.com/apk/res/android"  
  33. package = "org.jssec.android.intent.maliciousactivity"  
  34. android:versionCode= "1"  
  35. android:versionName= "1.0" >
  36.  
  37. <uses-sdk
  38. android:minSdkVersion= "8"  
  39. android:targetSdkVersion= "15" />
  40.  
  41. <application
  42. android:icon= "@drawable/ic_launcher"  
  43. android:label= "@string/app_name"  
  44. android:theme= "@style/AppTheme" >
  45. <activity
  46. android:name= ".MaliciousActivity"  
  47. android:label= "@string/title_activity_main" >
  48. <intent-filter>
  49. <action android:name= "android.intent.action.MAIN" />
  50.  
  51. <category android:name= "android.intent.category.LAUNCHER" />
  52. </intent-filter>
  53. </activity>
  54. </application>
  55.  
  56. <uses-permission android:name= "android.permission.GET_TASKS" />
  57.  
  58. </manifest>
  59. MaliciousActivity.java
  60.  
  61. [java]
  62. package org.jssec.android.intent.maliciousactivity;
  63. import java.util.List;
  64. import android.app.Activity;
  65. import android.app.ActivityManager;
  66. import android.content.Intent;
  67. import android.os.Bundle;
  68. import android.util.Log;
  69. public   class MaliciousActivity extends Activity {
  70. @Override  
  71. public   void onCreate(Bundle savedInstanceState) {
  72. super .onCreate(savedInstanceState);
  73. setContentView(R.layout.malicious_activity);
  74. ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
  75. List<ActivityManager.RecentTaskInfo> list = activityManager
  76. .getRecentTasks( 100 , ActivityManager.RECENT_WITH_EXCLUDED);
  77. for (ActivityManager.RecentTaskInfo r : list) {
  78. Intent intent = r.baseIntent;
  79. Log.v( "baseIntent" , intent.toString());
  80. }
  81. }
  82. }
  83.  
  84. package org.jssec.android.intent.maliciousactivity;
  85. import java.util.List;
  86. import android.app.Activity;
  87. import android.app.ActivityManager;
  88. import android.content.Intent;
  89. import android.os.Bundle;
  90. import android.util.Log;
  91. public   class MaliciousActivity extends Activity {
  92. @Override  
  93. public   void onCreate(Bundle savedInstanceState) {
  94. super .onCreate(savedInstanceState);
  95. setContentView(R.layout.malicious_activity);
  96. ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
  97. List<ActivityManager.RecentTaskInfo> list = activityManager
  98. .getRecentTasks( 100 , ActivityManager.RECENT_WITH_EXCLUDED);
  99. for (ActivityManager.RecentTaskInfo r : list) {
  100. Intent intent = r.baseIntent;
  101. Log.v( "baseIntent" , intent.toString());
  102. }
  103. }
  104. }

 

9. Possibility of Intent data being lost in LogCat

If the code is like the following, the data sent in the Intent will be automatically written to LogCat

  1. [java]
  2. Uri uri = Uri.parse( "mailto:[email protected]" );
  3. Intent intent = new Intent(Intent.ACTION_SENDTO, uri);
  4. startActivity(intent);
  5.  
  6. Uri uri = Uri.parse( "mailto:[email protected]" );
  7. Intent intent = new Intent(Intent.ACTION_SENDTO, uri);
  8. startActivity(intent);
  9.  
  10.  
  11. If you do it like this, you can avoid
  12.  
  13. [java]
  14. Uri uri = Uri.parse( "mailto:" );
  15. Intent intent = new Intent(Intent.ACTION_SENDTO, uri);
  16. intent.putExtra(Intent.EXTRA_EMAIL, new String[] { "[email protected]" });
  17. startActivity(intent);
  18.  
  19. Uri uri = Uri.parse( "mailto:" );
  20. Intent intent = new Intent(Intent.ACTION_SENDTO, uri);
  21. intent.putExtra(Intent.EXTRA_EMAIL, new String[] { "[email protected]" });
  22. startActivity(intent);

<<:  Memory leaks from entry to mastery: basic knowledge

>>:  Talking about Android security 1——Activity hijacking and user prevention

Recommend

Do you really know how to set promotion goals for your APP?

Nowadays, many newcomers who are engaged in app p...

Because I saw something strange, my memory before the age of 3 was deleted?

If I think about it carefully, the first time I h...

JDI and JOLED to merge in last-ditch effort to promote Japan Display

In the 1990s, Japan was the leader in the global ...

Summary of Web App Development Skills

1. META/LINK related: 1. Baidu prohibits transcod...

How to increase the click-through rate of Tik Tok short videos?

Today I will share with you (what types of Tik To...

Soul-searching question: How can humans make robots "moral"?

With the rapid development of artificial intellig...

Internet celebrity fox died in the snow? Stop feeding wild animals!

On December 26, the topic "Internet celebrit...

How to do data analysis for information flow promotion? Avoid these 4 pitfalls!

If you work in bidding, how can you grow into a p...

Case Study: Analysis of Jiliwawa’s Distribution System

Jiliwulala is an online children's enlightenm...