LSPosed-Hook加固应用

前言

在对加固应用进行Hook时,如果直接对应用中的函数进行Hook,则会报下图所示的ClassNotFoundException错误.

ClassNotFoundException

出现上述错误的原因就是类加载器ClassLoader在加固应用启动时切换导致的问题,我们知道App中所有类都是由对应的ClassLoader加载到ART虚拟机的,如果ClassLoader不正确,那么一定找不到对应的类.LSPosed在注入进程时App的Application类并未完成加载,这也就导致真实用于加载App业务相关类的ClassLoader并未出现,最终导致无法完成App业务函数的Hook.

下面提供两种方式来对加固应用进行Hook.

测试Apk

example.apk

方式一

通过对Android下的加固应用进行分析,可以知道壳程序总是通过在应用进程最先获得执行权限的Application类中的attachBaseContext和onCreate函数中完成对真实Dex的释放以及ClassLoader的切换.故我们可以通过对加固应用Application类的attachBaseContext或onCreate函数进行Hook,来得到真实App的上下文,再通过上下文来获取真实代码释放后的ClassLoader,用于后续的函数Hook.

其示例代码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
package com.example.luoxposeddemo;

import android.app.Application;
import android.content.Context;
import android.util.Log;

import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;

public class LuoHook implements IXposedHookLoadPackage {
    private final String TAG = "[LuoXposed]";

    @Override
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
        if (lpparam.packageName.equals("com.hay.dreamlover")) {
            Log.i(TAG, "Enter Hook");
            //com.stub.StubApp
            Class applicationClazz = lpparam.classLoader.loadClass("com.stub.StubApp");
            XposedHelpers.findAndHookMethod(applicationClazz, "attachBaseContext", Context.class, new XC_MethodHook() {
                @Override
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                    super.beforeHookedMethod(param);
                    Log.i(TAG, "Enter com.stub.StubApp.attachBaseContext");
                }

                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    super.afterHookedMethod(param);
                    Log.i(TAG, "Leave com.stub.StubApp.attachBaseContext");

                    Context context = (Context) param.args[0];
                    //获取真实业务代码的classLoader
                    ClassLoader finalClassLoader = context.getClassLoader();
                    Class initActivityClazz = finalClassLoader.loadClass("com.fanwe.hybrid.activity.InitActivity");
                    XposedBridge.hookAllMethods(initActivityClazz, "onCreate", new XC_MethodHook() {
                        @Override
                        protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                            super.beforeHookedMethod(param);
                            Log.i(TAG, "attachBaseContext Enter com.fanwe.hybrid.activity.InitActivity.onCreate");
                        }

                        @Override
                        protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                            super.afterHookedMethod(param);
                            Log.i(TAG, "attachBaseContext Leave com.fanwe.hybrid.activity.InitActivity.onCreate");
                        }
                    });
                }
            });
        }
    }
}

方式二

上面的方式一不具有通用性,一旦加固厂商改变相应继承Application类的类名,那上面的方式就失效了.下面介绍一种通用的解决任意加固应用函数的Hook方式.

Android App的启动流程如下:

App启动流程

App被Zygote进程孵化后,通过ActivityThread.main函数进入App的世界.ActivityThread这个类十分重要,它会根据ActivityManager发送的请求对activities、broadcast Receviers等操作进行调度和执行.其中performLaunchActivity()函数用于响应Activity相关的操作.另外ActivityThread类中还存在着一个Application类型的mInitialApplication成员,应用程序中有且只有一个Application组件,而Application对象中就存储着当前的ClassLoader,考虑到App在响应Activity消息时,真实App的代码已经被释放到内存中,此时通过mInitialApplication成员获取应用当前的ClassLoader,即可完成对真实App业务代码的Hook.

其示例代码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package com.example.luoxposeddemo;

import android.app.Application;
import android.content.Context;
import android.util.Log;

import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;

public class LuoHook implements IXposedHookLoadPackage {
    private final String TAG = "[LuoXposed]";

    @Override
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
        if (lpparam.packageName.equals("com.hay.dreamlover")) {
            Log.i(TAG, "Enter Hook");
            Class activityThreadClazz = lpparam.classLoader.loadClass("android.app.ActivityThread");
            XposedBridge.hookAllMethods(activityThreadClazz, "performLaunchActivity", new XC_MethodHook() {
                @Override
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                    super.beforeHookedMethod(param);
                    Log.i(TAG, "Enter android.app.ActivityThread.performLaunchActivity");
                    
                    Application mInitialApplication = (Application) XposedHelpers.getObjectField(param.thisObject, "mInitialApplication");
                    ClassLoader finalClassLoader = mInitialApplication.getClassLoader();
                    Class initActivityClazz = finalClassLoader.loadClass("com.fanwe.hybrid.activity.InitActivity");
                    //Log.i(TAG, initActivityClazz.toString());
                    XposedBridge.hookAllMethods(initActivityClazz, "onCreate", new XC_MethodHook() {
                        @Override
                        protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                            super.beforeHookedMethod(param);
                            Log.i(TAG, "performLaunchActivity Enter com.fanwe.hybrid.activity.InitActivity.onCreate");
                        }

                        @Override
                        protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                            super.afterHookedMethod(param);
                            Log.i(TAG, "performLaunchActivity Leave com.fanwe.hybrid.activity.InitActivity.onCreate");
                        }
                    });
                }

                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    super.afterHookedMethod(param);
                    Log.i(TAG, "Leave android.app.ActivityThread.performLaunchActivity");
                }
            });
        }
    }
}

至此,无论任何类型的App,只要存在一个Activity,按照上述方式进行Hook,理论上都可以完美解决.


相关内容

0%