獲取DNS解析時間
阿新 • • 發佈:2019-02-07
結論:
在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); } } } }