Author: geneblue
Blog: https://geneblue.github.io/
代码下载地址:这里
MainActivity类
下面从主函数MainActivity开始入手分析:
MainActivity主要是处理页面上的一些控件。modifyMac()方法是关键,主要是通过调用PrivacyManager类中的setValue()方法,设置mac值。
PrivacyManager类没有做任何实际处理,只是调用了PrivacyService中的getSetting()和setValue()方法。 #### XParam类 XParam类是非常基础的参数类,这个类里主要是通过Xposed提供的XC_MethodHook类的内部类MethodHookParam获取hook方法参数,如方法method,对象thisObject,方法调用的参数args,返回的对象result,异常抛出情况throwable等。
从图可以看出,XParam类使用的字段和方法。fromXposed()方法就是将MethodHookParam类中关于被hook的方法信息(上述)赋值给XParam的字段,并返回一个XParam对象。doesReturn()方法判断是否有返回的hook的方法,doesThrow()方法判断hook的方法是否抛出了异常。
XGene类
以下是程序在Xposed中的入口类XGene
XGene类中主要实现了定义服务(AIDL)的注册和方法的hook操作。从上图可以看出,XGene类实现了两个接口。XposedHookedLoadPackage接口定义了加载应用程序包的时候执行怎样的用户操作,具体实现是XGene中的handleLoadPackage()方法,在这里,这个方法什么都没做;IXposedHookZygoteInit接口主要定义了hook Zygote初始化的过程,具体的实现在XGene类的initZygote()方法中。initZygote()方法实现了定义的服务(AIDL)的注册工作,将自定义的服务注册到系统SystemServer类中作为系统服务。在应用程序调用SystemServer中的方法时会首先调用定义的方法,这样就可以达到返回虚假值得目的。这是程序的一个关键点,以下是它的实现代码:
public void initZygote(StartupParam startupParam) throws Throwable {
try {
Class<?> cSystemServer = Class
.forName("com.android.server.SystemServer");
Method mMain = cSystemServer.getDeclaredMethod("main",
String[].class);
// 使用Xposed来hook
XposedBridge.hookMethod(mMain, new XC_MethodHook() {
protected void beforeHookedMethod(MethodHookParam param)
throws Throwable {
PrivacyService.register(); // 服务注册
}
});
} catch (Throwable e) {
}
hookAll(XContextImpl.getInstances(), "1"); //XContextImpl类必须存
}
StrartupParam类是接口IXposedHookZygoteInit的一个内部类,只定义了一个String类型的字段modulePath,在这里并未使用到。代码开始通过Class类的静态方法forName()获取了SystemServer类,然后使用java反射机制获取到SystemServer对象的main方法,这也是Zygote创建System_Server进程的入口点函数,之后调用XposedBridge中的静态方法hookMethod对main方法进行hook,具体的操作是在调用main方法之前就注册我们定义的服务(AIDL)。接下来hook XContextImpl类,XContextImpl中的getInstances()方法返回一个含有XContextImpl对象的list,然后对该list中的每一项都进行hook操作。具体的hook方法最终都转到hook(final XHook hook,ClassLoader classLoader,String secret)方法中。接下来具体分析这个方法。注意这个时候Zygote还未创建System_Server进程,所以这个时候注册的服务就可以作为系统的服务。
hook(final XHook hook,ClassLoader classLoader,String secret)方法共传递进来三个参数,分别是不能再扩展的XHook类,类加载器和一个String的值,这个String类型的值在这里没有用到。该方法的具体实现代码如下:
private static void hook(final XHook hook, ClassLoader classLoader,
String secret) {
try {
//1
XC_MethodHook methodHook = new XC_MethodHook() {
protected void beforeHookedMethod(MethodHookParam param)
throws Throwable {
try {
if (Process.myUid() <= 0)
return;
XParam xParam = XParam.fromXposed(param);
hook.before(xParam);
if (xParam.hasResult())
param.setResult(xParam.getResult());
if (xParam.hasThrowable())
param.setThrowable(xParam.getThrowable());
param.setObjectExtra("xextra", xParam.getExtras());
} catch (Throwable ex) {
}
}
protected void afterHookedMethod(MethodHookParam param)
throws Throwable {
if (!param.hasThrowable()) {
try {
if (Process.myUid() <= 0)
return;
XParam xParam = XParam.fromXposed(param);
xParam.setExtras(param.getObjectExtra("xextra"));
hook.after(xParam);
if (xParam.hasResult())
param.setResult(xParam.getResult());
if (xParam.hasThrowable())
param.setThrowable(xParam.getThrowable());
} catch (Throwable ex) {
}
}
}
};
//2
// 使用findClass方法找到要hook的类
Class<?> hookClass = null;
try {
hookClass = findClass(hook.getClassName(), classLoader);
} catch (Throwable ex) {
}
//3
List<Member> listMember = new ArrayList<Member>();
Class<?> clazz = hookClass;
while (clazz != null) {
if (hook.getMethodName() == null) {
// 当hook类的构造方法修饰符是public时,就将该构造方法放到listMember中
for (Constructor<?> constructor : clazz
.getDeclaredConstructors()) {
if (Modifier.isPublic(constructor.getModifiers()) ? hook
.isVisible() : !hook.isVisible())
listMember.add(constructor);
}
break;
} else {
// 当hook类clazz的方法就是要hook的方法,并且该方法不是抽象方法时,就将该方法放到listMember中
for (Method method : clazz.getDeclaredMethods())
if (method.getName().equals(hook.getMethodName())
&& !Modifier.isAbstract(method.getModifiers()))
listMember.add(method);
}
clazz = clazz.getSuperclass();
}
//4
// Hook members
for (Member member : listMember)
try {
// 方法是抽象方法就略过
if (Modifier.isAbstract(member.getModifiers()))
;
else
// 当不是抽象方法时就hook
XposedBridge.hookMethod(member, methodHook);
} catch (NoSuchFieldError ex) {
} catch (Throwable ex) {
}
// 以下代码好像没用
if (listMember.isEmpty()
&& !hook.getClassName()
.startsWith("com.google.android.gms"))
if (!hook.isOptional())
;
} catch (Throwable ex) {
}
}
在标号1处实现的代码主要是在hook方法的前后设定好参数信息,标号2处寻找到要hook的类名,标号3处寻找将要hook类的构造方法和非抽象方法。在标号4处就将获取到的方法进行hook操作,而且这里用到了标号1处的代码。
XHook类
上述中经常使用XHook类,那这个类是干什么用的还需要解释:
XHook类是一个抽象类,则其他的类如XContextImpl,XTelephonyManager,XWifiManager都继承了这个抽象类,并实现了该抽象类中的抽象方法。可以重左图中看到,该类有两个构造方法,这两个构造方法都是对变量的赋值。Optional()方法的作用未知,isVisible()方法判断要hook的方法是否是可见的属性为public就可见。getClassName(),before(),after()方法都是抽象方法,都在子类中实现。
在分析过程中结合实验验证(将PrivacyService.java中的有关虚假信息文件读写操作的代码屏蔽掉,并另外实现一个程序通过系统api获取mac值,结果无法获取mac值),猜想此module注册成系统服务后,ServiceManager中提供的服务如WifiManager,TelephonyManager等如果要调用方法,都会被我们注册的服务拦截到,并将存储的值作为调用方法的请求值。接下来就看看PrivacyService.java中都做了哪些操作:
PrivacyService类
这个类主要是AIDL接口的实现,并将设定的虚假值写到文件中,同时做了读取虚假值的操作。rigister()方法首先在本地创建了一个文件夹,这个文件夹里存放的就是以后设定虚假值的文件,然后该方法使用java反射机制调用android.os.ServiceManager类中的addService方法将定义的服务注册到系统中,作为系统级服务。getClient()方法通过反射调用android.os.ServiceManager类中的getService()方法来获取定义服务实体的代理接口。getSetting()方法通过AIDL接口实现类mPrivacyService获取存储在本地的虚假值。createInfoFile()和getInfoFile()负责本地虚假值文件的读和写。接口实现类mPrivacyService就是通过上述两个方法的文件读写操作来设定虚假值。setValue()方法通过接口实现类来设定虚假值。
最后还剩下三个文件XContextImpl.java,XWifiManager.java和XTelephonyManager.java还有待分析,这三个类都是XHook抽象类的子类: Context的理解和ContextImpl是什么见文档,XContextImpl类主要在after()方法中调用XGene类中的handleGetSystemService()方法。XWifiManager类和XTelephonyManager类大致相同。