xposed框架
1、概述
hook是Windows中提供的一种用以替换DOS下“中断”的系统机制。每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权。这时钩子函数即可以加工处理(改变)该消息,也可以不作处理而继续传递该消息,还可以强制结束消息的传递。
Xposed框架核心思想:在于将java层普通函数注册成本地JNI方法,以此来变相实现HOOk机制。
1.1 核心思想
一、Xposed框架的核心原理
修改/system/bin/app-process程序。在android执行第一个程序zygote进程之前进行截获,改变执行流程,进入到自身的Main函数体内。Main函数执行体内主要完成以下四步流程:
- initNative(). 为了方便Xposed框架的native方法对上层Java方法的调用,在该部分对相关native方法进行初始化工作。
- initXbrigdeZygote().主要hook几个涉及到应用进程创建,启动的关键类。
- loadModules,读取系统中放置的hook模块,然后把该模块的路径写进conf/moudules.list中。
- Xposed框架加载完毕后,将执行权还给第一个程序zygote,完成正常的系统启动流程。
(XPOSED的安装器替换安卓系统的app_process文件,从而实现对系统的接管,通过回调模块的方式来达到不用修改APK就能改变其表现行为的目的。该框架比较成熟,对应的模块也非常多,常用的还有模拟地理位置,伪装手机设备信息等,脑洞是非常之大,基本上能想到的都能做到。)
app_process其实是一个程序,存放在systen/bin目录下的,作用就是启动一个程序,启动zygote进程,所有App启动。app_process只要找到需要运行程序的main函数,也就是入口函数,然后执行,他不仅能执行C/C++程序,也可以执行Java程序。
在Android中,zygote是整个系统创建新进程的核心进程。
Android系统是基于Linux内核的,而在Linux系统中,所有的进程都是Zygoteinit进程的子孙进程,也就是说,所有的进程都是直接或者间接地由Zygoteinit进程fork出来的。
由于Xposed框架Hook了Android的核心进程Zygote,而其他应用启动都是从Zygote进程fork而来,就够达到针对系统上所有的应用程序进程的Hook。
1.2 Xposed内部执行流程
创建新应用,获取包名等信息。
调用XC_LoadPackage.callAll,依次执行各hook模块的代码。
如果有包名匹配的hook模块,则注册模块中要hook的方法为本地方法。
当该方被调用的时候,转移到本地xposedCallHandler。
xposedCallHandler回调上层handlerHookedMethod(因为加载的hook模块代码,一些变量都存储在java层)。
handlerHookedMethod执行加载的各hook模块
beforeHookedMethod 该方法在hook目标方法执行前调用,其中,参数param指的是目标方法的相关参数、回调、方法等信息
afterHookedMethod该方法在hook目标方法执行后调用,其中,参数param指的是目标方法的相关参数、回调、方法等信息。
Xposed运行多个模块对同一个方法进行hook时,框架就会根据Xposed模块的优先级来排序,在具有a.before、a.after、b.before、b.after的情 况下,运行的先后顺序如下:(a优先级高于b)
before -> b.before ->originalMethod -> b.after -> a.after
1 |
|
学会这些方法,在结合逆向smail的一些知识,应该可以满足大多数java层的hook了。
2. API
IXposedHookLoadPackage
方法: handleLoadPackage,这个方法用于在加载应用程序的包的时候执行用户的操作
参数说明: final LoadPackageParam lpparam 这个参数包含了加载的应用程序的一些基本信息.
1
2
3
4
5
6
7
8
9
10
11
12
13
14方法: findAndHookMethod,这是一个辅助方法,可以通过静态导入使用
参数说明: findAndHookMethod(Class<?> clazz, ClassLoader, methodName, Object…, parameterTypesAndCallback )
Class<?> clazz, //需要 Hook 的类名;
ClassLoader,//类加载器,可以设置为 null String;
methodName, //需要 Hook 的方法名;
Object…,//对象类型;
parameterTypesAndCallback //回调方法XposedBridge
方法: log(),打日志。
该方法可以将 log 信息以及 Throwable 抛出的异常信息输出到标准的logcat 以及/data/xposed/debug.log 这个文件中
无参方法: hookAllMethods/hookAllConstructors,该方法可以用来 hook 某个类中的所有方法或者构造函数,但是不同的Rom(非Android原生 Rom)会有不同的变种。
XC_LoadPackage.LoadPackageParam
fields type description packageName String 应用包名 processName String 应用加载后的进程名 classLoader ClassLoader 应用的classloader appInfo ApplicationInfo 应用的信息,包括verisonCode,uid等
IXposedHookInitPackageResources
XposedHookInitPackageResources的resparam参数有以下两个字段
field type description packageName String 应用包名 res XResources 资源相关
XposedHelpers
查找类
1
2
3
4//className 完整类名,classLoader 类加载器(app应用的类加载器)
public static Class<?> findClass(String className, ClassLoader classLoader)
public static Class<?> findClassIfExists(String className, ClassLoader classLoader)查找字段
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// clazz 通过findClass获取,调用findFieldRecursiveImpl获取
private static Field findFieldRecursiveImpl(Class<?> clazz, String fieldName) throws NoSuchFieldException {
try {
return clazz.getDeclaredField(fieldName);
} catch (NoSuchFieldException e) {
while (true) {
clazz = clazz.getSuperclass();
if (clazz == null || clazz.equals(Object.class))
break;
try {
return clazz.getDeclaredField(fieldName);
} catch (NoSuchFieldException ignored) {}
}
throw e;
}
}
public static Field findFirstFieldByExactType(Class<?> clazz, Class<?> type)
//获取实例字段的引用
public static Object getObjectField(Object obj, String fieldName)
/*获取Field的方法,具体实现是在findFieldRecursiveImpl方法里面获取,外部不能访问,Field是通过getDeclaredField获取,所以只能获取static类型的字段。indFirstFieldByExactType()方法是匹配Field的classType,如果类型一样,则返回该字段,该方法的局限性是只能获取到第一个匹配到的字段,后面相同类型的无法获取*/设置字段
1
2
3
4public static void setXXXField(Object obj, String fieldName, XXX value)
public static void setStaticXXXField(Class<?> clazz, String fieldName, XXX value)
public static Xxx getXxxField(Object obj, String fieldName)
public static Xxx getStaticXxxField(Class<?> clazzj, String fieldName)查找方法
1
2
3public static Method findMethodExact(Class<?> clazz, String methodName, Object... parameterTypes)
public static Method findMethodExactIfExists(Class<?> clazz, String methodName, Object... parameterTypes)调用方法
1
2
3
4
5
6
7public static Object callMethod(Object obj, String methodName, Object... args)
public static Object callMethod(Object obj, String methodName, Class<?>[] parameterTypes, Object... args)
public static Object callStaticMethod(Class<?> clazz, String methodName, Object... args)
public static Object callStaticMethod(Class<?> clazz, String methodName, Class<?>[] parameterTypes, Object... args)调用实例/静态Method,返回值为方法返回值
1
2
3
4
5public static XC_MethodHook.Unhook findAndHookMethod(Class<?> clazz, String methodName, Object... parameterTypesAndCallback)
//通过className和classLoader获取Class<?> ,再调用上面的方法
public static XC_MethodHook.Unhook findAndHookMethod(String className, ClassLoader classLoader, String methodName, Object... parameterTypesAndCallback)Hook方法的一个方法,其中parameterTypesAndCallback和findConstructorExact方法的parameterTypes类似,不过这里可变数组最后一个对象必须为XC_MethodHook对象或者其子类,前面的对象为参数的ClassType或者类字符串,在hook成功后,当调用hook的方法时,会在XC_MethodHook回调。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22public abstract class XC_MethodHook extends XCallback {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
//方法调用前的回调
super.beforeHookedMethod(param);
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
//方法调用后的回调
super.afterHookedMethod(param);
}
}
public abstract class XC_MethodReplacement extends XC_MethodHook{
@Override
protected Object replaceHookedMethod(MethodHookParam param) throws Throwable {
//带返回值的方法执行时调用
return null;
}
}
hook构造器
1
2
3
4
5
6public static Constructor<?> findConstructorExact(Class<?> clazz, Object... parameterTypes)
public static Constructor<?> findConstructorExactIfExists(Class<?> clazz, Object... parameterTypes)
public static Constructor<?> findConstructorBestMatch(Class<?> clazz, Class<?>... parameterTypes)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24/*获取Constructor方法,其中Object... parameterTypes 是一个Object的可变数组,parameterTypes由Class<?>的可变数组 ,完整类名字符串和XC_MethodHook抽象类 组成。XC_MethodHook为可选参数,并且总在最后一个。XC_MethodHook在这里并无实际意义,Class<?>[] 为相应的构造函数的类型,通过一个例子简单说明,有一个T类,构造函数有三个参数,可以用以下几种方式获取:*/
public class T {
String str;
Context mContext;
View mView;
public T(String str, Context context, View view) {
this.str = str;
mContext = context;
mView = view;
}
}
//方式1:
Constructor constructor = XposedHelpers.findConstructorExact(clazz, String.class, Context.class, View.class);
//方式2:
Constructor constructor = XposedHelpers.findConstructorExact(T.class, String.class, "android.content.Context", View.class);
//方式3:(XC_MethodHook无实际意义)
Constructor constructor = XposedHelpers.findConstructorExact(T.class, String.class, "android.content.Context", View.class, new XC_MethodHook() {});
3. Hook加固APP
一.hook原理
使用加固之后的应用的classloader会被换成其加固应用本身的,所以只需要在hook的时候把classloader换成壳的就可以了。
二.具体操作和分析
被加固的应用是可以反编译的,反编译之后dex里面只有很少的几个类,比较重要的就是壳入口这个类,可以在这个类里面的里面去获取context参数,然后就可以通过context获得到壳的类加载器,之后只需要用这个类加载器来hook就可以成功的hook到加固的app
注:
Android源码中android.app.Applocation 188行,attachBaseContext方法在Application的attach方法被调用,基本上所有的壳都会在attachBaseContext里完成代码解密并且内存加载dex,所以在
attachBaseContext执行之后,拿到的classloader就已经加载过加固dex的classloader。
1 |
|
3. 获取所有类
1 |
|
4. Hook所有方法
1 |
|
5、XposedHook程序源码
HookDemo.java
1 |
|
1 |
|