0%

Xposed Hook 匿名内部类

写 Xposed 插件的时候如何 Hook 一个匿名内部类中的一个方法。

匿名内部类

匿名内部类适用于创建一次性使用的类。在创建类的时候就会立刻创建实例。匿名内部类没有构造器,所以一般都是通过接口来创建匿名内部类。

1
2
3
4
new 实现接口() | 父类构造器 (实参列表)
{
//匿名内部类的类体部分
}

Hook技巧

下面我将用这个文件举例子如何来 hook 匿名内部类 REQUEST_INTERCEPTOR。全部代码可以参见:ServiceGenerator.java

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
package com.wifi.reader.network.service;

public class ServiceGenerator {
private static final java.math.BigDecimal BD32 = new java.math.BigDecimal(32);
private static final okhttp3.Cache CACHE = new okhttp3.Cache(com.wifi.reader.application.WKRApplication.c().getCacheDir(), 10485760);
public static final okhttp3.OkHttpClient HTTP_CLIENT = new okhttp3.OkHttpClient.Builder().connectTimeout(5, java.util.concurrent.TimeUnit.SECONDS).readTimeout(60, java.util.concurrent.TimeUnit.SECONDS).addInterceptor(REQUEST_INTERCEPTOR).addNetworkInterceptor(RESPONSE_INTERCEPTOR).sslSocketFactory(com.wifi.reader.glide.https.SSLSocketClient.getSSLSocketFactory()).hostnameVerifier(com.wifi.reader.glide.https.SSLSocketClient.getHostnameVerifier()).cache(CACHE).retryOnConnectionFailure(true).build();
private static final okhttp3.logging.HttpLoggingInterceptor LOGGING = new okhttp3.logging.HttpLoggingInterceptor().setLevel(okhttp3.logging.HttpLoggingInterceptor.Level.HEADERS);
private static final okhttp3.Interceptor REQUEST_INTERCEPTOR = new okhttp3.Interceptor() {
public okhttp3.Response intercept(okhttp3.Interceptor.Chain chain) throws java.io.IOException {
}

private java.lang.String getValidateCode(java.lang.String str) {
java.lang.Object c = com.wifi.reader.config.User.a().c();
java.lang.Object e = com.wifi.reader.config.User.a().e();
try {
e = c32to10(e);
} catch (java.lang.Throwable e2) {
android.util.Log.e(com.wifi.reader.network.service.ServiceGenerator.TAG, "decode device id failed", e2);
}
java.lang.StringBuilder stringBuilder = new java.lang.StringBuilder();
if (!android.text.TextUtils.isEmpty(c)) {
stringBuilder.append(c);
}
if (!android.text.TextUtils.isEmpty(e)) {
stringBuilder.append(e);
}
if (!android.text.TextUtils.isEmpty(str)) {
stringBuilder.append(str);
}
return com.wifi.reader.util.CryptoUtils.a(stringBuilder.toString());
}
};
}

我们可以看下 okhttp3.Interceptor 这个接口。

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
package okhttp3;

public interface Interceptor {

public interface Chain {
okhttp3.Call call();

int connectTimeoutMillis();

@javax.annotation.Nullable
okhttp3.Connection connection();

okhttp3.Response proceed(okhttp3.Request request) throws java.io.IOException;

int readTimeoutMillis();

okhttp3.Request request();

okhttp3.Interceptor.Chain withConnectTimeout(int i, java.util.concurrent.TimeUnit timeUnit);

okhttp3.Interceptor.Chain withReadTimeout(int i, java.util.concurrent.TimeUnit timeUnit);

okhttp3.Interceptor.Chain withWriteTimeout(int i, java.util.concurrent.TimeUnit timeUnit);

int writeTimeoutMillis();
}

okhttp3.Response intercept(okhttp3.Interceptor.Chain chain) throws java.io.IOException;
}

这验证了之前说了,匿名内部类的创建方式之一就是通过接口来实现。

hook 的方式很简单,只需要用 $ 来连接即可。比如这是第一个匿名内部类,那么就是 $1。如果是第二个匿名内部类那就是 $2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
ClassLoadMonitor.addClassLoadMonitor("com.wifi.reader.network.service.ServiceGenerator$1", new ClassLoadMonitor.OnClassLoader() {
@Override
public void onClassLoad(Class<?> aClass) {
XposedHelpers.findAndHookMethod(aClass, "getValidateCode", String.class, new SingletonXC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
Log.i("lianshang", "getValidateCode参数:" + JSONObject.toJSONString(param.args));
Log.i("lianshang", "结果:" + param.getResult());
Log.i("lianshang", "method:" + param.method.toString());
Log.i("lianshang", "trace:" + LogUtil.getTrack());
}
});
}
});

假设你算不出来这是第几个匿名内部类,那么你可以 hook 这个方法会调用的类,然后通过 hook 其他被调用的类来打印调用栈也可以知道这个匿名内部类的名字。

参考资料