/******************************************************************************* * 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.Method; import android.app.PendingIntent; import android.location.Criteria; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.os.Looper; import android.util.Log; import com.saurik.substrate.MS; import com.thesis.asa.Utilities; import com.thesis.asa.location.LocationSettings; public class LocationHook extends Hook { private static Class<?> locationManager; private static FakeLocationListener fakeListener; public static void hook() { MS.hookClassLoad("android.location.LocationManager", new MS.ClassLoadHook() { public void classLoaded(Class<?> _clazz) { fakeListener = new FakeLocationListener(); locationManager = _clazz; hookRequestUpdates(); hookGetLastKnownLocation(); } }); } protected static Location getLocationIn(double latitude, double longitude, String provider) { Location location = new Location(provider); location.setLatitude(latitude); location.setLongitude(longitude); location.setAltitude(0); location.setAccuracy(0.2F); location.setTime(System.currentTimeMillis()); return location; } protected static void hookGetLastKnownLocation() { Method method; try { Class<?>[] params = new Class[1]; params[0] = String.class; method = locationManager.getMethod("getLastKnownLocation", params); } catch (NoSuchMethodException e) { method = null; Log.d(Utilities.ERROR, Log.getStackTraceString(e)); } if (method != null) { MS.hookMethod(locationManager, method, new MS.MethodAlteration<LocationManager, Location>() { public Location invoked(final LocationManager hooked, final Object... args) throws Throwable { Object[] properties = getProperties(LocationSettings.class .getName()); if (properties[0].equals("Real")) return invoke(hooked, args); return getLocationIn( Double.parseDouble((String) properties[0]), Double.parseDouble((String) properties[1]), (String) args[0]); } }); } } private static void hookRequestUpdates() { Method[] methods = new Method[2]; Class<?>[] params = null; for (int i = 0; i < methods.length; i++) { Method method = null; if (i == 0) { params = new Class[6]; params[0] = String.class; params[1] = Criteria.class; params[2] = long.class; params[3] = float.class; params[4] = boolean.class; params[5] = PendingIntent.class; } if (i == 1) { params = new Class[7]; params[0] = String.class; params[1] = Criteria.class; params[2] = long.class; params[3] = float.class; params[4] = boolean.class; params[5] = LocationListener.class; params[6] = Looper.class; } try { methods[i] = locationManager.getDeclaredMethod( "_requestLocationUpdates", params); method = methods[i]; } catch (NoSuchMethodException e) { methods[i] = null; Log.d(Utilities.ERROR, "No such method i = " + i + " _requestLocationUpdates"); } if (method != null) { MS.hookMethod(locationManager, method, new MS.MethodAlteration<LocationManager, Void>() { public Void invoked(final LocationManager hooked, final Object... args) throws Throwable { String classname = LocationSettings.class.getName(); Object[] properties = getProperties(classname); if (properties[0].equals("Real")) return invoke(hooked, args); Location location = getLocationIn( Double.parseDouble((String) properties[0]), Double.parseDouble((String) properties[1]), (String) args[0]); try { LocationListener listener = (LocationListener) args[5]; fakeListener.setListener(listener); fakeListener.setLocation(location); args[5] = fakeListener; } catch (Exception e) { try { // TODO: we are not doing anything in // this case Log.d(Utilities.DEBUG, "_requestUpdates was called with PendingIntent, ASA"); PendingIntent intent = (PendingIntent) args[5]; } catch (Exception e2) { Log.d(Utilities.ERROR, "The argument should be LocationListener or PendingIntent"); } } return invoke(hooked, args); } }); } } } }