Hook Technology-intercept the Activity Startup Process and hook-activity

Source: Internet
Author: User

Hook Technology-intercept the Activity Startup Process and hook-activity
1. Principles of searching for Hook points

Android mainly relies on the source code class of the analysis system. First, we need to find the Hook object, which I call a Hook point. What kind of object is better to Hook? Naturally, it is easy to find objects. What types of objects are easy to find? Static variables and Singleton; in a process, static variables and Singleton variables are relatively difficult to change, so they are very easy to locate, while common objects are either unsigned, it is easy to change. We can find the so-called Hook points based on this principle.

2. Search for Hook points

Generally, when you click a Button, the Activity jump starts. What happens in the middle? How can we Hook it to implement interception of Activity startup?

public void start(View view) {        Intent intent = new Intent(this, OtherActivity.class);        startActivity(intent);}

Our goal is to intercept the startActivity method, trace the source code, and find that the last Activity to be started is implemented by execStartActivity of the Instrumentation class. In fact, this class is equivalent to the intermediary who starts the Activity. It is used to start the Activity.

1 public ActivityResult execStartActivity (2 Context who, IBinder contextThread, IBinder token, Activity target, 3 Intent intent, int requestCode, Bundle options) {4 IApplicationThread whoThread = (IApplicationThread) contextThread; 5 .... 6 try {7 intent. migrateExtraStreamToClipData (); 8 intent. prepareToLeaveProcess (who); 9 10 // use ActivityManagerNative. getDefault () gets an object and starts to start the new Activity11 int res Ult = ActivityManagerNative. getDefault () 12. startActivity (whoThread, who. getBasePackageName (), intent, 13 intent. resolveTypeIfNeeded (who. getContentResolver (), 14 token, target! = Null? Target. mEmbeddedID: null, 15 requestCode, 0, null, options); 16 17 18 checkStartActivityResult (result, intent); 19} catch (RemoteException e) {20 throw new RuntimeException ("Failure from system", e); 21} 22 return null; 23}

For ActivityManagerNative, you are familiar with the Activity/Service Startup Process.

public abstract class ActivityManagerNative extends Binder implements IActivityManager

Inherits the Binder and implements an IActivityManager interface, which is the "Stub" class for remote service communication. A complete aid l has two parts, one is a Stub that communicates with the server, and the other is a Proxy that communicates with the client. ActivityManagerNative is Stub. Read the source code and find that there is an ActivityManagerProxy in the ActivityManagerNative file.

1 static public IActivityManager getDefault() {2       return gDefault.get();3   }

ActivityManagerNative. getDefault () is an IActivityManager object, which is started by IActivityManager. The implementation class of IActivityManager is ActivityManagerService, and ActivityManagerService is in another process, starting all activities is a cross-process communication process. Therefore, the actual starting Activity is started through the remote service ActivityManagerService.

 private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {        protected IActivityManager create() {            IBinder b = ServiceManager.getService("activity");            if (false) {                Log.v("ActivityManager", "default service binder = " + b);            }            IActivityManager am = asInterface(b);            if (false) {                Log.v("ActivityManager", "default service = " + am);            }            return am;}

In fact, gDefalut uses Singleton to implement the Singleton mode. Internally, we can see that the Binder object of the AMS remote service is obtained from ServiceManager, and then the asInterface method is used to convert it into a localized object, we aim to intercept startActivity, so we can change the IActivityManager object to achieve this. gDefault is static here. According to the Hook principle, this is a better Hook point.

3. Hook startActivity and output logs

We first implement a small requirement to print a log when starting the Activity.

1 public class HookUtil {2 3 private Class <?> ProxyActivity; 4 5 private Context context; 6 7 public HookUtil (Class <?> ProxyActivity, Context context) {8 this. proxyActivity = proxyActivity; 9 this. context = context; 10} 11 12 public void hookAms () {13 14 // One-way reflection until the IActivityManager object is obtained 15 try {16 Class <?> ActivityManagerNativeClss = Class. forName ("android. app. activityManagerNative "); 17 Field defaultFiled = ActivityManagerNativeClss. getDeclaredField ("gDefault"); 18 defaultFiled. setAccessible (true); 19 Object defaultValue = defaultFiled. get (null); 20 // reflection SingleTon21 Class <?> SingletonClass = Class. forName ("android. util. singleton "); 22 Field mInstance = SingletonClass. getDeclaredField ("mInstance"); 23 mInstance. setAccessible (true); 24 // The ActivityManager Object 25 is obtained here. iActivityManagerObject = mInstance. get (defaultValue); 26 27 28 // start the dynamic proxy, replace the real ActivityManager with the proxy object, and surpass the sea for 29 Class <?> IActivityManagerIntercept = Class. forName ("android. app. IActivityManager "); 30 31 AmsInvocationHandler handler = new AmsInvocationHandler (iActivityManagerObject); 32 33 Object proxy = Proxy. newProxyInstance (Thread. currentThread (). getContextClassLoader (), new Class <?> [] {IActivityManagerIntercept}, handler); 34 35 // replace 36 mInstance with this object. set (defaultValue, proxy); 37 38 39} catch (Exception e) {40 e. printStackTrace (); 41} 42}

 

1 private class AmsInvocationHandler implements InvocationHandler {2 3 private Object iActivityManagerObject; 4 5 private AmsInvocationHandler (Object iActivityManagerObject) {6 this. iActivityManagerObject = iActivityManagerObject; 7} 8 9 @ Override10 public Object invoke (Object proxy, Method method, Object [] args) throws Throwable {11 12 Log. I ("HookUtil", method. getName (); 13 // here I want to do something 14 if ("s TartActivity ". contains (method. getName () {15 Log. e ("HookUtil", "Activity started"); 16 Log. e ("HookUtil", "This is a tour !!! "); 17} 18 return method. invoke (iActivityManagerObject, args); 19} 20} 21}

It should be easy to understand with comments. configure it in Application

1 public class MyApplication extends Application {2 3     @Override4     public void onCreate() {5         super.onCreate();6         HookUtil hookUtil=new HookUtil(SecondActivity.class, this);7         hookUtil.hookAms();8     }9 }

Check the execution result:

We can see that startActivity is successfully hooked and a log is output. With the above foundation, we can start something useful now. The Activity can be started without being registered in the list file. How can this problem be solved?

4. Start the Activity without registration

As follows, TargetActivity is not registered in the list file. How can I start TargetActivity?

public void start(View view) {        Intent intent = new Intent(this, TargetActivity.class);        startActivity(intent);    }

This can be done in this way. The above process has intercepted the startup Activity process. In invoke, we can get the intent information of the startup parameter, so here, we can construct a false intent of the Activity information by ourselves. The Activity started by this Intent is registered in the list file. When it is actually started (after the ActivityManagerService verifies the list file ), use a real Intent to replace the Intent of the proxy, and then start the agent.

First, obtain the intent information of the actual startup parameter.

1 @ Override 2 public Object invoke (Object proxy, Method method, Object [] args) throws Throwable {3 if ("startActivity ". contains (method. getName () {4 // replace 5 Intent intent = null; 6 int index = 0; 7 for (int I = 0; I <args. length; I ++) {8 Object arg = args [I]; 9 if (arg instanceof Intent) {10 // The Intent parameter 11 intent = (Intent) of startActivity is found) args [I]; 12 // This intent cannot be started, because Acitivity does not register 13 index = I in the inventory file; 14} 15} 16 17 // forge a proxy Intent. The proxy Intent starts proxyActivity18 Intent proxyIntent = new Intent (); 19 ComponentName componentName = new ComponentName (context, proxyActivity ); 20 proxyIntent. setComponent (componentName); 21 proxyIntent. putExtra ("oldIntent", intent); 22 args [index] = proxyIntent; 23} 24 25 return method. invoke (iActivityManagerObject, args); 26}

With the above two steps, the Intent of this proxy can be verified by ActivityManagerService, because I have registered

<activity android:name=".ProxyActivity" />
 

In order not to start ProxyActivity, we need to find a suitable time to change the true Intent to start the Activity we really want to start. Our friends who have read the Activity startup process know that this process is implemented by Handler to send messages. However, according to the Code of Handler to process messages, the distribution and processing of messages are ordered, the following is the code for Handler to process messages:

public void dispatchMessage(Message msg) {        if (msg.callback != null) {            handleCallback(msg);        } else {            if (mCallback != null) {                if (mCallback.handleMessage(msg)) {                    return;                }            }            handleMessage(msg);        }    }

When handler processes messages, it first checks whether the callback interface is implemented. If there is an implementation, it will directly execute the interface method, then the handleMessage method, and finally the handleMessage method that is rewritten, we generally rewrite the handleMessage method most of the time, while the main thread of ActivityThread uses the rewrite method, which has the lowest priority, we can implement interfaces to replace the Handler processing process. For details, see chapter (1) of the Handler series of Android source code parsing-Message global pool

1 public void hookSystemHandler () {2 try {3 4 Class <?> ActivityThreadClass = Class. forName ("android. app. activityThread "); 5 Method currentActivityThreadMethod = activityThreadClass. getDeclaredMethod ("currentActivityThread"); 6 currentActivityThreadMethod. setAccessible (true); 7 // get the main thread Object 8 Object activityThread = currentActivityThreadMethod. invoke (null); 9 // obtain the mH Field 10 Field mH = activityThreadClass. getDeclaredField ("mH"); 11 mH. setAccessible (true); 12 // get Handler13 Handler handler = (Handler) mH. get (activityThread); 14 // obtain the original mCallBack Field 15 Field mCallBack = Handler. class. getDeclaredField ("mCallback"); 16 mCallBack. setAccessible (true); 17 // The CallBack object 18 mCallBack is set here. set (handler, new ActivityThreadHandlerCallback (handler); 19 20} catch (Exception e) {21 e. printStackTrace (); 22} 23}

Custom Callback class

1 private class ActivityThreadHandlerCallback implements Handler. callback {2 3 private Handler handler; 4 5 private ActivityThreadHandlerCallback (Handler handler) {6 this. handler = handler; 7} 8 9 @ Override10 public boolean handleMessage (Message msg) {11 Log. I ("HookAmsUtil", "handleMessage"); 12 // replace the previous Intent13 if (msg. what == 100) {14 Log. I ("HookAmsUtil", "lauchActivity"); 15 handleLauchActivity (MS G); 16} 17 18 handler. handleMessage (msg); 19 return true; 20} 21 22 private void handleLauchActivity (Message msg) {23 Object obj = msg. obj; // ActivityClientRecord24 try {25 Field intentField = obj. getClass (). getDeclaredField ("intent"); 26 intentField. setAccessible (true); 27 Intent proxyInent = (Intent) intentField. get (obj); 28 Intent realIntent = proxyInent. getParcelableExtra ("oldIntent"); 29 if (realInten T! = Null) {30 proxyInent. setComponent (realIntent. getComponent (); 31} 32} catch (Exception e) {33 Log. I ("HookAmsUtil", "lauchActivity falied"); 34} 35 36} 37}

Finally, inject

1 public class MyApplication extends Application {2 @ Override 3 public void onCreate () {4 super. onCreate (); 5 // This ProxyActivity has been registered in the list file. In the future, all Activitiy can use ProxyActivity without declaration, bypassing monitoring 6 HookAmsUtil hookAmsUtil = new HookAmsUtil (ProxyActivity. class, this); 7 hookAmsUtil. hookSystemHandler (); 8 hookAmsUtil. hookAms (); 9} 10} 11 1

Run and click the button in MainActivity to jump to TargetActivity.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.