获取DNS解析时间

结论:

在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);
            }
        }
    }
}

你可能感兴趣的:(其他)