Android页面劫持问题整理 您所在的位置:网站首页 劫持app软件 Android页面劫持问题整理

Android页面劫持问题整理

2023-12-06 14:35| 来源: 网络整理| 查看: 265

苦难磨炼一些人,也毁灭另一些人。——富勒

什么是Activity页面劫持

APP正常的Activity界面被恶意攻击者替换上仿冒的恶意Activity界面进行攻击和非法用途。界面劫持攻击通常难被识别出来,其造成的后果不仅会给用户带来严重损失,更是移动应用开发者们的恶梦。举个例子来说,当用户打开安卓手机上的某一应用,进入到登陆页面,这时,恶意软件侦测到用户的这一动作,立即弹出一个与该应用界面相同的Activity,覆盖掉了合法的Activity,用户几乎无法察觉,该用户接下来输入用户名和密码的操作其实是在恶意软件的Activity上进行的,最终会发生什么就可想而知了。

Activity界面被劫持的原因

很多网友发现,如果在启动一个Activity时,给它加入一个标志位FLAG_ACTIVITY_NEW_TASK,就能使它置于栈顶并立马呈现给用户。针对这一操作,假使这个Activity是用于盗号的伪装Activity呢?在Android系统当中,程序可以枚举当前运行的进程而不需要声明其他权限,这样子我们就可以写一个程序,启动一个后台的服务,这个服务不断地扫描当前运行的进程,当发现目标进程启动时,就启动一个伪装的Activity。如果这个Activity是登录界面,那么就可以从中获取用户的账号密码。

常见的攻击手段 监听系统Logocat日志,一旦监听到发生Activity界面切换行为,即进行攻击,覆盖上假冒Activity界面实施欺骗。开发者通常都知道,系统的Logcat日志会由ActivityManagerService打印出包含了界面信息的日志文件,恶意程序就是通过Logocat获取这些信息,从而监控客户端的启动、Activity界面的切换。监听系统API,一旦恶意程序监听到相关界面的API组件调用,即可发起攻击。逆向APK,恶意攻击者通过反编译和逆向分析APK,了解应用的业务逻辑之后针对性的进行Activity界面劫持攻击 防护措施

在用户使用app的时候,如果被恶意程序劫持跳转到别的界面,这个时候我们就要做出预警提示用户,告诉用户当前界面已经不是我们的app有潜在的危险。代码的工作原理很简单就是在我们所写的activity对象的onResume里启动一个task定时监测这个页面是否被劫持,在onDestroy里关掉这个task。

判断是否被劫持的依据就是当前的最顶层的activity所在的进程是否和当前app进程一致,代码如下:

package com.tuhu.zpos.utils; import android.app.ActivityManager; import android.app.KeyguardManager; import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.os.Build; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collections; import java.util.List; import static android.content.pm.PackageManager.*GET_UNINSTALLED_PACKAGES*; public class AntiHiJack { public static final String *TAG*= "AntiHiJack"; // white name list private static List *safePackages*; static { *safePackages*= new ArrayList(); } */*** * * 配置白名单* * */* public static void configSafePackages(List packages) { *safePackages*= packages; } private static PackageManager *pm*; private List mlistAppInfo; */*** * * 检测当前Activity是否安全* * */* public static boolean checkActivity(Context context) { boolean safe = false; *pm*= context.getPackageManager(); int flag = *GET_UNINSTALLED_PACKAGES*;//7.0之后被遗弃 if (Build.VERSION.*SDK_INT*>= Build.VERSION_CODES.*N*) { flag = PackageManager.*MATCH_UNINSTALLED_PACKAGES*; } // 查询所有已经安装的应用程序 List listAppcations = *pm*.getInstalledApplications(flag); Collections.*sort*(listAppcations, new ApplicationInfo.DisplayNameComparator(*pm*));// 排序 //List appInfos = new ArrayList(); // 保存过滤查到的AppInfo //appInfos.clear(); for (ApplicationInfo app : listAppcations) {//这个排序必须有. //得到所有的系统程序包名放进白名单里面. if ((app.flags & ApplicationInfo.*FLAG_SYSTEM*) != 0) { //appInfos.add(getAppInfo(app)); *safePackages*.add(app.packageName); } } ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.*ACTIVITY_SERVICE*); String runningActivityPackageName; int sdkVersion; try { sdkVersion = Build.VERSION.*SDK_INT*; } catch (NumberFormatException e) { sdkVersion = 0; } if (sdkVersion >= 21) { //获取系统api版本号,如果是5x系统就用这个方法获取当前运行的包名 runningActivityPackageName = *getCurrentPkgName*(context); } else { //如果是4x及以下,用这个方法. runningActivityPackageName = activityManager.getRunningTasks(1).get(0).topActivity.getPackageName(); } if (runningActivityPackageName != null) {//有些情况下在5x的手机中可能获取不到当前运行的包名,所以要非空判断。 WLLog.*e*("currentPackage", "currentPackage:" + runningActivityPackageName + " 当前应用的包名:" + context.getPackageName()); if (runningActivityPackageName.equals(context.getPackageName())) { safe = true; } // 白名单比对 for (String safePack : *safePackages*) { WLLog.*e*("safePack", safePack); if (safePack.equals(runningActivityPackageName)) { safe = true; } } } return safe; } public static String getCurrentPkgName(Context context) {//5x系统以后利用反射获取当前栈顶activity的包名. ActivityManager.RunningAppProcessInfo currentInfo = null; Field field = null; int START_TASK_TO_FRONT = 2; String pkgName = null; try { field = ActivityManager.RunningAppProcessInfo.class.getDeclaredField( "processState");//通过反射获取进程状态字段. } catch (Exception e) { e.printStackTrace(); } ActivityManager am = (ActivityManager) context.getSystemService(Context.*ACTIVITY_SERVICE*); List appList = am.getRunningAppProcesses(); ActivityManager.RunningAppProcessInfo app; for (int i = 0; i //表示前台运行进程. Integer state = null; try { state = field.getInt(app);//反射调用字段值的方法,获取该进程的状态. } catch (Exception e) { e.printStackTrace(); } if (state != null && state == START_TASK_TO_FRONT) {//根据这个判断条件从前台中获取当前切换的进程对象. currentInfo = app; break; } } } if (currentInfo != null) { pkgName = currentInfo.processName; } return pkgName; } */*** * * 当前停留在desktop* * ** * ****@param***context 上下文* * */* public static boolean isHome(Context context) { ActivityManager mActivityManager = (ActivityManager) context.getSystemService(Context.*ACTIVITY_SERVICE*); List rti = mActivityManager.getRunningTasks(1); return *getHomes*(context).contains(rti.get(0).topActivity.getPackageName()); } */*** * * 获得属于desktop应用的应用包名称* * ** * ****@return***返回包含所有包名的字符串列表* * */* private static List getHomes(Context context) { List names = new ArrayList(); PackageManager packageManager = context.getPackageManager(); Intent intent = new Intent(Intent.*ACTION_MAIN*); intent.addCategory(Intent.*CATEGORY_HOME*); List resolveInfo = packageManager.queryIntentActivities(intent, PackageManager.*MATCH_DEFAULT_ONLY*); for (ResolveInfo ri : resolveInfo) { names.add(ri.activityInfo.packageName); } return names; } */*** * * 判断当前是否在锁屏再解锁状态* * ** * ****@param***context 上下文* * */* public static boolean isReflectScreen(Context context) { KeyguardManager mKeyguardManager = (KeyguardManager) context.getSystemService(Context.*KEYGUARD_SERVICE*); return mKeyguardManager.inKeyguardRestrictedInputMode(); }

通过工具类中的checkActivity方法,监测顶层视图所在的进程名称;有一些是补充方法,可以用可不用;

攻击场景模拟

模拟攻击场景,使用的是一个简单的servcie服务,不断的在后台获取当前系统中运行的程序的包名称,当找到目标程序并且监测到进入前台的时候,就会在目标程序的页面弹出一个伪程序页面,代码如下:

private var mTsk = object : TimerTask() { override fun run() { /** * 进行劫持 * @param processName */ fun hijacking(processName: String) { Log.w(“hijacking”, “有程序要悲剧了……”) if (!(application as HijackApplication).hasProgressJacked(processName)) { Log.w(“hijacking”, “悲剧正在发生”) val jackingIsComing = Intent() jackingIsComing.component = ComponentName(“com.zh.hijeckservice”, “com.zh.hijeckservice.BadActivity”) jackingIsComing.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) application.startActivity(jackingIsComing) (application as HijackApplication).addProgressJacked(processName) Log.w(“hijacking”, “已经劫持”) } } val activityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager val appProcessInfos: List = activityManager.runningAppProcesses // 枚举进程 Log.w(“hijacking", "正在枚举进程") for (appProcessInfo in appProcessInfos) { // 如果APP在前台 if (appProcessInfo.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND) { if (mSadStories.contains(appProcessInfo.processName)) { // 进行劫持 hijacking(appProcessInfo.processName) } else { Log.w("hijacking", appProcessInfo.processName) } } } } }

当然,这个服务我们可以做成一个开机启动的效果,具体如何实现就不赘述了。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有