package mobi.acpm.inspeckage.hooks; import android.os.Build; import java.io.DataOutputStream; import java.net.HttpURLConnection; import java.net.URI; import java.net.URL; import java.security.SecureRandom; import java.security.cert.X509Certificate; import java.util.List; import java.util.Map; import javax.net.ssl.KeyManager; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import de.robv.android.xposed.XC_MethodHook; import de.robv.android.xposed.XposedBridge; import de.robv.android.xposed.callbacks.XC_LoadPackage; import mobi.acpm.inspeckage.Module; import static de.robv.android.xposed.XposedBridge.hookAllConstructors; import static de.robv.android.xposed.XposedHelpers.findAndHookMethod; import static de.robv.android.xposed.XposedHelpers.findClass; import static de.robv.android.xposed.XposedHelpers.getObjectField; /** * Created by acpm on 14/02/16. */ public class HttpHook extends XC_MethodHook { public static final String TAG = "Inspeckage_Http:"; public static void initAllHooks(final XC_LoadPackage.LoadPackageParam loadPackageParam) { try { final Class<?> httpUrlConnection = findClass("java.net.HttpURLConnection", loadPackageParam.classLoader); hookAllConstructors(httpUrlConnection, new XC_MethodHook() { protected void beforeHookedMethod(MethodHookParam param) throws Throwable { if (param.args.length != 1 || param.args[0].getClass() != URL.class) { return; } XposedBridge.log(TAG + "HttpURLConnection: " + param.args[0] + ""); } }); } catch (Error e) { Module.logError(e); } XC_MethodHook RequestHook = new XC_MethodHook() { protected void beforeHookedMethod(MethodHookParam param) throws Throwable { HttpURLConnection urlConn = (HttpURLConnection) param.thisObject; if (urlConn != null) { StringBuilder sb = new StringBuilder(); boolean connected = (boolean)getObjectField(param.thisObject, "connected"); if(!connected){ Map<String, List<String>> properties = urlConn.getRequestProperties(); if (properties != null && properties.size() > 0) { for (Map.Entry<String, List<String>> entry : properties.entrySet()){ sb.append(entry.getKey()+": "+entry.getValue()+", "); } /** Collection<List<String>> coll = properties.values(); if (coll != null && coll.size() > 0) { for (List<String> ls : coll) { for (String s : ls) { sb.append(s+", "); } } } **/ } DataOutputStream dos = (DataOutputStream) param.getResult(); XposedBridge.log(TAG + "REQUEST: method=" + urlConn.getRequestMethod() + " " + "URL=" + urlConn.getURL().toString() + " " + "Params=" + sb.toString()); } } } }; XC_MethodHook ResponseHook = new XC_MethodHook() { protected void beforeHookedMethod(MethodHookParam param) throws Throwable { HttpURLConnection urlConn = (HttpURLConnection) param.thisObject; if (urlConn != null) { StringBuilder sb = new StringBuilder(); int code = urlConn.getResponseCode(); if(code==200){ Map<String, List<String>> properties = urlConn.getHeaderFields(); if (properties != null && properties.size() > 0) { for (Map.Entry<String, List<String>> entry : properties.entrySet()) { sb.append(entry.getKey() + ": " + entry.getValue() + ", "); } } } XposedBridge.log(TAG + "RESPONSE: method=" + urlConn.getRequestMethod() + " " + "URL=" + urlConn.getURL().toString() + " " + "Params=" + sb.toString()); } } }; try { final Class<?> okHttpClient = findClass("com.android.okhttp.OkHttpClient", loadPackageParam.classLoader); if(okHttpClient != null) { findAndHookMethod(okHttpClient, "open", URI.class, new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { URI uri = null; if (param.args[0] != null) uri = (URI) param.args[0]; XposedBridge.log(TAG + "OkHttpClient: " + uri.toString() + ""); } }); } } catch (Error e) { Module.logError(e); } try { if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) { findAndHookMethod("libcore.net.http.HttpURLConnectionImpl", loadPackageParam.classLoader, "getOutputStream", RequestHook); } else { //com.squareup.okhttp.internal.http.HttpURLConnectionImpl final Class<?> httpURLConnectionImpl = findClass("com.android.okhttp.internal.http.HttpURLConnectionImpl", loadPackageParam.classLoader); if(httpURLConnectionImpl != null) { findAndHookMethod("com.android.okhttp.internal.http.HttpURLConnectionImpl", loadPackageParam.classLoader, "getOutputStream", RequestHook); findAndHookMethod("com.android.okhttp.internal.http.HttpURLConnectionImpl", loadPackageParam.classLoader, "getInputStream", ResponseHook); } } } catch (Error e) { Module.logError(e); } findAndHookMethod(SSLContext.class, "init", KeyManager[].class, TrustManager[].class, SecureRandom.class, new XC_MethodHook() { protected void beforeHookedMethod(MethodHookParam param) throws Throwable { KeyManager[] km = (KeyManager[]) param.args[0]; TrustManager[] tm_ = (TrustManager[]) param.args[1]; if (tm_ != null && tm_[0] != null) { X509TrustManager tm = (X509TrustManager) tm_[0]; X509Certificate[] chain = new X509Certificate[]{}; XposedBridge.log(TAG + "Possible pinning."); boolean check = false; /** try { tm.checkClientTrusted(chain, ""); tm.checkServerTrusted(chain, ""); }catch (CertificateException ex){ check = true; } if(check){ XposedBridge.log(TAG + " Custom TrustManager - Possible pinning."); }else { XposedBridge.log(TAG + " App not verify SSL."); }**/ } } }); } }