/******************************************************************************* * Copyright (c) 2014 CodingBad. * All rights reserved. This file is part of ASA. * * ASA is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * ASA is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ASA. If not, see <http://www.gnu.org/licenses/>. * * Contributors: * Ayelén Chavez - ashy.on.line@gmail.com * Joaquín Rinaudo - jmrinaudo@gmail.com ******************************************************************************/ package com.thesis.asa.hook; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Date; import java.util.List; import android.content.Context; import android.net.wifi.ScanResult; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.util.Log; import com.saurik.substrate.MS; import com.thesis.asa.Utilities; import com.thesis.asa.provider.SettingsDB; import com.thesis.asa.wifi.WifiSettings; public class WifiHook extends Hook { protected static final String[] columns = SettingsDB.WIFI_TABLE_COLUMNS; protected static long lastTimeChecked = 0; protected static Object[] properties; // protected static Context currentContext = null; protected static void hookUtilsGetWifiIpAddresses() { MS.hookClassLoad("com.android.settings.Utils", new MS.ClassLoadHook() { public void classLoaded(Class<?> utils) { Method method; try { Class<?>[] params = new Class[1]; params[0] = Context.class; method = utils.getMethod("getWifiIpAddresses", params); } catch (NoSuchMethodException e) { Log.d(Utilities.ERROR, Log.getStackTraceString(e)); method = null; } if (method != null) { MS.hookMethod(utils, method, new MS.MethodAlteration<Object, String>() { public String invoked(final Object hooked, final Object... args) throws Throwable { Integer ip = 0; Context context = (Context) args[0]; String result = invoke(hooked, args); if (result == null) return null; final Object[] properties = Hook .queryConfigurationFromASA(context, new WifiSettings(context)); String value = ((String) properties[2]) .trim(); ip = (Integer) getHookedResultForIP(value, getRealIPFrom(result)); return Utilities.getFormatedIpFromIp(ip); } }); } } }); } protected static void hookUtilsGetDefaultWifiIpAddresses() { MS.hookClassLoad("com.android.settings.Utils", new MS.ClassLoadHook() { public void classLoaded(Class<?> utils) { Method method; try { Class<?>[] params = new Class[1]; params[0] = Context.class; method = utils.getMethod("getDefaultIpAddresses", params); } catch (NoSuchMethodException e) { Log.d(Utilities.ERROR, Log.getStackTraceString(e)); method = null; } if (method != null) { MS.hookMethod(utils, method, new MS.MethodAlteration<Object, String>() { public String invoked(final Object hooked, final Object... args) throws Throwable { Integer ip = 0; Context context = (Context) args[0]; String result = invoke(hooked, args); if (result == null) return null; final Object[] properties = Hook .queryConfigurationFromASA(context, new WifiSettings(context)); String value = ((String) properties[2]) .trim(); ip = (Integer) getHookedResultForIP(value, getRealIPFrom(result)); return Utilities.getFormatedIpFromIp(ip); } }); } } }); } public static void hook() { hookUtilsGetWifiIpAddresses(); hookUtilsGetDefaultWifiIpAddresses(); MS.hookClassLoad("android.net.wifi.WifiManager", new MS.ClassLoadHook() { public void classLoaded(Class<?> wifiManager) { hookWifiConfiguredNetworksMethod(wifiManager); hookWifiScanResultsMethod(wifiManager); } }); MS.hookClassLoad("android.net.wifi.WifiInfo", new MS.ClassLoadHook() { public void classLoaded(Class<?> wifiInfo) { hookWifiMethod(wifiInfo, "getBSSID"); hookWifiMethod(wifiInfo, "getIpAddress"); hookWifiMethod(wifiInfo, "getMacAddress"); hookWifiMethod(wifiInfo, "getSSID"); } }); } protected static int fakeIP() { return getRealIPFrom("192.168.0.2"); } protected static String fakeDataFor(String methodName) { if (methodName.equals("getBSSID")) { return "aa:aa:aa:aa:aa:aa"; } else { if (methodName.equals("getMacAddress")) { return "bb:bb:bb:bb:bb:bb"; } else { if (methodName.equals("getSSID")) { return "Wifi"; } else { Log.d(Utilities.ERROR, "No matched column for method " + methodName + "in Wifi resource"); } } } return ""; } protected static Object getGeneralHookedResult(String methodName, String value, String result) { if (value.equals("Fake")) { return fakeDataFor(methodName); } else { if (value.equals("Real")) return result; else { return value.replace("\"", ""); } } } protected static Object getHookedResultForIP(String value, int result) { if (value.equals("Fake")) return fakeIP(); else { if (value.equals("Real")) return result; else { return getRealIPFrom(value); } } } private static int getRealIPFrom(String ipAddress) { String[] octets = ipAddress.split("\\."); return (Integer.parseInt(octets[3]) << 24) + (Integer.parseInt(octets[2]) << 16) + (Integer.parseInt(octets[1]) << 8) + Integer.parseInt(octets[0]); } private static void hookWifiConfiguredNetworksMethod(Class<?> clazz) { final String methodName = "getConfiguredNetworks"; Method method; try { Class<?>[] params = new Class[0]; method = clazz.getMethod(methodName, params); } catch (NoSuchMethodException e) { method = null; Log.d(Utilities.ERROR, "No such method: getConfiguredNetworks"); } if (method != null) { MS.hookMethod(clazz, method, new MS.MethodAlteration<WifiManager, List<Object>>() { public List<Object> invoked(final WifiManager hooked, final Object... args) throws Throwable { List<Object> result = invoke(hooked, args); if (result == null) return null; Object[] properties = getProperties(WifiSettings.class .getName()); int index = 0; for (Object property : properties) { String column = columns[index]; index++; if (column.equals(methodName)) { String value = ((String) property).trim(); if (value.equals("Real")) return result; else if (value.equals("Fake")) return new ArrayList<Object>(); else { // Custom case String[] propertyIds = Utilities .stringToArray(value); List<String> ssids = new ArrayList<String>(); List<Object> filteredSSIDS = new ArrayList<Object>(); List<String> originalSSIDS = new ArrayList<String>(); for (int i = 0; i < propertyIds.length; i++) { ssids.add(propertyIds[i].trim()); } for (Object res : result) { if (ssids .contains(((WifiConfiguration) res).SSID)) filteredSSIDS.add(res); originalSSIDS .add(((WifiConfiguration) res).SSID); } result = filteredSSIDS; } break; } } return result; } }); } } private static void hookWifiScanResultsMethod(Class<?> clazz) { final String methodName = "getScanResults"; Method method; try { Class<?>[] params = new Class[0]; method = clazz.getMethod(methodName, params); } catch (NoSuchMethodException e) { method = null; Log.d(Utilities.ERROR, "No such method: " + methodName); } if (method != null) { MS.hookMethod(clazz, method, new MS.MethodAlteration<WifiManager, List<Object>>() { public List<Object> invoked(final WifiManager hooked, final Object... args) throws Throwable { List<Object> result = invoke(hooked, args); if (result == null) return null; Constructor<ScanResult> constructor = null; try { constructor = ScanResult.class.getConstructor(String.class,String.class,String.class,Integer.TYPE,Integer.TYPE); } catch (NoSuchMethodException e1) { Log.d(Utilities.ERROR,"Problem getting ScanResult constructor through Java Reflection"); } Object[] properties = getProperties(WifiSettings.class .getName()); int index = 0; for (Object property : properties) { String column = columns[index]; index++; if (column.equals(methodName)) { String value = ((String) property).trim(); if (value.equals("Real")) return result; else if (value.equals("Fake")) return new ArrayList<Object>(); else { // Custom case List<String> propertyIds = Utilities. getScannedWifisFrom(value); List<Object> scannedNetworks = new ArrayList<Object>(); for (int i = 0; i < propertyIds.size(); i++) { Object[] constructor_args = new Object[5]; String[] scan = Utilities .stringToArray(propertyIds.get(i)); constructor_args[0] = ((String) scan[0]).replace("\"","").trim(); constructor_args[1] = scan[1].trim(); constructor_args[2] = scan[2].trim(); constructor_args[3] = Integer.parseInt(((String) scan[3]).trim()); constructor_args[4] = Integer.parseInt(((String) scan[4]).trim()); scannedNetworks.add(constructor.newInstance(constructor_args)); } result = scannedNetworks; } break; } } return result; } }); } } protected Object configuration; private static void hookWifiMethod(Class<?> clazz, final String methodName) { Method method; try { Class<?>[] params = new Class[0]; method = clazz.getMethod(methodName, params); } catch (NoSuchMethodException e) { method = null; } if (method != null) { MS.hookMethod(clazz, method, new MS.MethodAlteration<WifiInfo, Object>() { public Object invoked(final WifiInfo hooked, final Object... args) throws Throwable { Object result = invoke(hooked, args); if (result == null) return result; long time = new Date().getTime(); if(properties == null || time - lastTimeChecked > Utilities.WIFI_CACHE_TIME_THRESHOLD){ lastTimeChecked = time; properties = getProperties(WifiSettings.class .getName()); } int index = 0; for (Object property : properties) { String column = columns[index]; index++; if (column.equals(methodName)) { String value = ((String) property).trim(); if (methodName.equals("getIpAddress")) { result = getHookedResultForIP(value, (Integer) result); } else { result = getGeneralHookedResult( methodName, value, (String) result); } break; } } if (result == null || result == "null") result = ""; return result; } }); } } }