结论:
在6.0及一下的系统中,系统代码中没有hook点,所有解析dns的方式都是通过调用静态方法的方法完成的,所以6.0及以下系统是拿不到dns的解析时间的,但是在7.0及以上系统中 拿到了dns的解析时间
方法:
- 在7.0手机尝试 通过设置错误的host 找到系统解析dns的方法,如下图

发现系统进行dns解析的主要方式是利用InetAddress类中的方法getAllByName(String host)
在这个方法中 我们惊奇的发现了一个变量impl,下面看看这个imp是个什么
太好了,居然是一个静态对象,上面我们知道getAllByName方法内调用了imp的lookupAllHostAddr方法,下面这个lookupAllHostAddr方法
继续寻找,在lookupAllHostAddr方法中调用了lookupHostByName方法
在lookupHostByName方法中 我们终于找到了系统解析dns的具体方式了,通过 InetAddress[] addresses = Libcore.os.android_getaddrinfo(host, hints, netId);这段代码拿到了InetAddress,这个就是解析dns的结果,为此我们只需要hook到imp这个静态对象并动态代理到lookupAllHostAddr这个方法即可,具体代码如下:
至此,在7.0及以上系统中 拿到了dns的解析时间 - 在6.0及一下系统通过上面方式尝试获取dns报错
在6.0上一样通过制造host异常,找到系统获取dns的方法
我们发现跟7.0的方法是一样的getAllByName ,下面看看方法的具体实现
居然是调用了静态的方法getAllByNameImp,继续看getAllByNameImp静态方法怎么写的
在getAllByNameImp方法中又是调用了静态的方法lookupHostByName,继续看
完了 在6.0及一下的系统中,系统代码中没有hook点,所有解析dns的方式都是通过调用静态方法的方法完成的,所以6.0及以下系统是拿不到dns的解析时间的
hook部分代码:
package com.hello2mao.xlogging.internal.dns;
import android.util.Log;
import com.hello2mao.xlogging.internal.TransactionsCache;
import com.hello2mao.xlogging.internal.util.DnsData;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.InetAddress;
/**
* Created by linyaokui on 18/9/12.
*/
public class DnsHook {
private static final String TAG = "test_hook_dns";
//调用此方法 hook到dns解析
public static void hook() {
try {
//拿到InetAddress类
Class<?> InetAddressClass = Class.forName("java.net.InetAddress");
//拿到InetAddress的静态属性impl(InetAddressImpl类型)
Field implField = InetAddressClass.getDeclaredField("impl");
implField.setAccessible(true);
//拿到InetAddressImpl对象
Object implFieldValue = implField.get(null);
//设置动态代理需要的InvocationHandler
DnsInvocationHandler handler = new DnsInvocationHandler(implFieldValue);
//拿到InetAddressImpl接口
Class<?> InetAddressImplIntercept = Class.forName("java.net.InetAddressImpl");
//设置impl的动态代理
Object proxy = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
new Class<?>[]{InetAddressImplIntercept}, handler);
//代理impl
implField.set(null, proxy);
} catch (Exception e) {
e.printStackTrace();
}
}
public static class DnsInvocationHandler implements InvocationHandler {
private Object implValue;
private DnsInvocationHandler(Object implValue) {
this.implValue = implValue;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Log.v(TAG, "hook成功");
Object result;
try {
if (method.getName().equals("lookupAllHostAddr")) {
//当拿到lookupAllHostAddr 方法时进行时间处理
//拿到nds解析的开始时间
long start = System.currentTimeMillis();
result = method.invoke(implValue, args);
//拿到dns解析的结束时间
long end = System.currentTimeMillis();
Log.v(TAG, (end - start) + "");
InetAddress[] address = (InetAddress[]) result;
//输出dns解析的hostName和hostAddress
if (address != null && address.length > 0) {
for (int i = 0; i < address.length; i++) {
Log.v(TAG, i + "--" + address[i].getHostName());
Log.v(TAG, i + "--" + address[i].getHostAddress());
}
}
TransactionsCache.addDnsData(address[0].getHostName(),
new DnsData(start, end));
return result;
} else {
return method.invoke(implValue, args);
}
} catch (Exception e) {
return method.invoke(implValue, args);
}
}
}
}
本文探讨了在Android 7.0及以上系统中如何通过hook技术捕获DNS解析时间,揭示了系统内部DNS解析机制,并提供了具体的代码实现。同时,指出在6.0及以下系统因静态方法调用限制无法直接获取解析时间。
622

被折叠的 条评论
为什么被折叠?



