├── .classpath ├── .project ├── .settings └── org.eclipse.jdt.core.prefs ├── AndroidManifest.xml ├── CydiaSubstrate.iml ├── LEEME.md ├── README.md ├── assets └── privacy.json ├── ic_launcher-web.png ├── libs ├── android-support-v4.jar └── substrate-api.jar ├── proguard-project.txt ├── res ├── drawable-hdpi │ └── ic_launcher.png ├── drawable-mdpi │ └── ic_launcher.png ├── drawable-xhdpi │ └── ic_launcher.png ├── drawable-xxhdpi │ └── ic_launcher.png ├── layout │ └── activity_main.xml ├── menu │ └── main.xml ├── values-sw600dp │ └── dimens.xml ├── values-sw720dp-land │ └── dimens.xml ├── values-v11 │ └── styles.xml ├── values-v14 │ └── styles.xml └── values │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml └── src └── ar └── fsadosky └── marvintoqueton ├── Main.java ├── MainActivity.java ├── MessageHandler.java ├── UpdateViewTask.java ├── Utils.java ├── hooks ├── AdapterViewHook.java ├── ButtonHook.java ├── CheckboxHook.java ├── DatePickerHook.java ├── EditTextHook.java ├── Hook.java ├── RadioGroupHook.java ├── SearchViewHook.java ├── SpinnerHook.java ├── TimePickerHook.java ├── ToggleButtonHook.java ├── ViewGroupHook.java └── ViewHook.java └── privacyhooks ├── ContactsHelper.java ├── DeviceDataHook.java ├── FakeLocationListener.java ├── LocationHook.java ├── PrivacyHook.java ├── Utils.java └── WifiHook.java /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | Marvin-toqueton 4 | 5 | 6 | 7 | 8 | 9 | com.android.ide.eclipse.adt.ResourceManagerBuilder 10 | 11 | 12 | 13 | 14 | com.android.ide.eclipse.adt.PreCompilerBuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.jdt.core.javabuilder 20 | 21 | 22 | 23 | 24 | com.android.ide.eclipse.adt.ApkBuilder 25 | 26 | 27 | 28 | 29 | 30 | com.android.ide.eclipse.adt.AndroidNature 31 | org.eclipse.jdt.core.javanature 32 | 33 | 34 | -------------------------------------------------------------------------------- /.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 3 | org.eclipse.jdt.core.compiler.compliance=1.6 4 | org.eclipse.jdt.core.compiler.source=1.6 5 | -------------------------------------------------------------------------------- /AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 21 | 24 | 25 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /CydiaSubstrate.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /LEEME.md: -------------------------------------------------------------------------------- 1 | # Marvin Toquetón # 2 | 3 | Herramienta de testing automático de GUI desarrollado para Marvin-dynamic-analyzer. 4 | 5 | Version 0.1 6 | 7 | El framework es utilizado para dos propósitos: 8 | * Hookear elementos de la UI para interactuar con ellos sin conocer el layout de las Views. 9 | * Modificar el acceso a identificadores específicos del dispositivo, contactos, información de la wifi e ubicación para permitir analizar si esos identificadores son transmitidos por la red o almacenados de forma insegura en el dispositivo. 10 | 11 | ## Implementación ## 12 | 13 | Toquetón instrumenta las siguientes Views para interactuar con la aplicación: 14 | 15 | * EditText 16 | * Checkbox 17 | * RadioGroup 18 | * ToggleButton 19 | * Spinner 20 | * DatePicker 21 | * TimePicker 22 | * Button 23 | * TextView 24 | * Menu 25 | * AdapterView 26 | * SearchView 27 | * ViewGroup 28 | * View 29 | 30 | Cuando una View es creada, un mensaje es enviado a un Handler que corre en el main thread de la aplicación y es responsable de interactuar con ella periódicamente. Un retraso aleatorio para interactuar con la View es ajustado cada vez dependiendo de la view y su visibilidad. 31 | 32 | Además, para extender la interacción con la aplicación, el fuzzer comienza una nueva actividad (no necesariamente exportada) continuamente cada cierto tiempo. 33 | 34 | Los métodos instrumentados para acceder a la información privada del dispositivo está basada el el proyecto [ASA](https://github.com/c0d1ngb4d/ASA/). Estos métodos hookeados devuelven la información leída desde un archivo denominado 'privacy.json' ubicado en la memoria externa del dispositivo. 35 | 36 | ## Requerimientos ## 37 | 38 | * Dispositivo rooteado con Android 4.3 o menor 39 | * Cydia Substrate 40 | 41 | ## Créditos ## 42 | * Joaquín Rinaudo ([@xeroxnir](https://www.twitter.com/xeroxnir)) 43 | * Juan Heguiabehere ([@jheguia](https://www.twitter.com/jheguia)) 44 | 45 | ## Contacto ## 46 | * Mandar un correo a stic en el dominio fundacionsadosky.org.ar 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Marvin Toquetón # 2 | 3 | Automated GUI testing utility developed for Marvin-dynamic-analyzer. 4 | 5 | Version 0.1 6 | 7 | The framework is used for two purposes: 8 | 9 | * Hook UI elements to interact with them without knowing the view layout. 10 | * Modify access to device specific identifiers, contacts, wifi and locations informations to be able to 11 | analyze if those identifiers are transmitted to the network or stored insecurely in the device 12 | 13 | ## Implementation description ## 14 | 15 | Toquetón instruments the following Views for interacting with the application: 16 | 17 | * EditText 18 | * Checkbox 19 | * RadioGroup 20 | * ToggleButton 21 | * Spinner 22 | * DatePicker 23 | * TimePicker 24 | * Button 25 | * TextView 26 | * Menu 27 | * AdapterView 28 | * SearchView 29 | * ViewGroup 30 | * View 31 | 32 | When a View is created, a message is send to a Handler running in the main thread of the application that is responsible of interacting with it periodically. A random delay for interacting with it is set depending on the type of view and it's visibility status. 33 | 34 | Also, in order to extend the interaction with the application, the fuzzer starts a new random activity (non necessarily exported) repeatedly. 35 | 36 | Instrumentation for methods that access to private information identifiers and resources is based in [ASA](https://github.com/c0d1ngb4d/ASA/) project. The methods hooked and the information return by hooks is read from a file stored in external storage named 'privacy.json'. 37 | 38 | ## Requirements ## 39 | 40 | * Android rooted device with 4.3 or lower 41 | * Cydia Substrate 42 | 43 | ## Credits ## 44 | * Joaquín Rinaudo ([@xeroxnir](https://www.twitter.com/xeroxnir)) 45 | * Juan Heguiabehere ([@jheguia](https://www.twitter.com/jheguia)) 46 | 47 | ## Who do I talk to? ## 48 | * Send an email to stic at fundacionsadosky.org.ar 49 | -------------------------------------------------------------------------------- /assets/privacy.json: -------------------------------------------------------------------------------- 1 | { 2 | "android.telephony.TelephonyManager" : { 3 | "getSimOperatorName" : "QUAM-SIM", 4 | "getSimOperator" : "72201", 5 | "getNetworkOperatorName" : "QUAM-NETWORK", 6 | "getNetworkOperator" : "72207" 7 | }, 8 | "com.android.internal.telephony.gsm.GSMPhone" : { 9 | "getDeviceId" : "352738061926670", 10 | "getImei" : "352738061926671", 11 | "getSubscriberId" : "722010000906017", 12 | "getLine1Number" : "1112341234" 13 | }, 14 | 15 | "com.android.internal.telephony.gsm.CDMAPhone" : { 16 | "getDeviceId" : "352738061926672", 17 | "getMeid" : "352738061926673", 18 | "getSubscriberId" : "722010000906017", 19 | "getLine1Number" : "541101010101" 20 | }, 21 | "com.android.internal.telephony.PhoneBase" : 22 | { 23 | "getIccSerialNumber" : "8954010111009060172f" 24 | 25 | }, 26 | "android.net.wifi.WifiInfo" : { 27 | "getBSSID" : "de:ad:be:ef:aa:aa", 28 | "getIpAddress" : "192.168.0.2", 29 | "getMacAddress" : "de:ad:be:ef:bb:bb", 30 | "getSSID" : "ThizIsMyWifi" 31 | }, 32 | 33 | "com.android.settings.Utils" : { 34 | "getWifiIpAddresses" : "192.168.0.2", 35 | "getDefaultIpAddresses" : "192.168.0.2" 36 | }, 37 | "android.location.LocationManager" : { 38 | "requestLocationUpdates" : "-34.603773, -58.381700", 39 | "getLastKnownLocation" : "-34.603773, -58.381700" 40 | }, 41 | "android.net.wifi.WifiManager" : { 42 | "getConfiguredNetworks" : "", 43 | "getScanResults" : "" 44 | } 45 | } -------------------------------------------------------------------------------- /ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/programa-stic/Marvin-toqueton/6e9710dc4b42e8f9b2f5326e0e2bcaf09aff60e4/ic_launcher-web.png -------------------------------------------------------------------------------- /libs/android-support-v4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/programa-stic/Marvin-toqueton/6e9710dc4b42e8f9b2f5326e0e2bcaf09aff60e4/libs/android-support-v4.jar -------------------------------------------------------------------------------- /libs/substrate-api.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/programa-stic/Marvin-toqueton/6e9710dc4b42e8f9b2f5326e0e2bcaf09aff60e4/libs/substrate-api.jar -------------------------------------------------------------------------------- /proguard-project.txt: -------------------------------------------------------------------------------- 1 | # To enable ProGuard in your project, edit project.properties 2 | # to define the proguard.config property as described in that file. 3 | # 4 | # Add project specific ProGuard rules here. 5 | # By default, the flags in this file are appended to flags specified 6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt 7 | # You can edit the include path and order by changing the ProGuard 8 | # include property in project.properties. 9 | # 10 | # For more details, see 11 | # http://developer.android.com/guide/developing/tools/proguard.html 12 | 13 | # Add any project specific keep options here: 14 | 15 | # If your project uses WebView with JS, uncomment the following 16 | # and specify the fully qualified class name to the JavaScript interface 17 | # class: 18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 19 | # public *; 20 | #} 21 | -------------------------------------------------------------------------------- /res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/programa-stic/Marvin-toqueton/6e9710dc4b42e8f9b2f5326e0e2bcaf09aff60e4/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/programa-stic/Marvin-toqueton/6e9710dc4b42e8f9b2f5326e0e2bcaf09aff60e4/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/programa-stic/Marvin-toqueton/6e9710dc4b42e8f9b2f5326e0e2bcaf09aff60e4/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/programa-stic/Marvin-toqueton/6e9710dc4b42e8f9b2f5326e0e2bcaf09aff60e4/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 10 | 11 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /res/menu/main.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /res/values-sw600dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /res/values-sw720dp-land/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 128dp 8 | 9 | 10 | -------------------------------------------------------------------------------- /res/values-v11/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /res/values-v14/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16dp 5 | 16dp 6 | 7 | 8 | -------------------------------------------------------------------------------- /res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | FuzzingHelper 5 | Settings 6 | Restart the phone! 7 | 8 | 9 | -------------------------------------------------------------------------------- /res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 14 | 15 | 16 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/ar/fsadosky/marvintoqueton/Main.java: -------------------------------------------------------------------------------- 1 | package ar.fsadosky.marvintoqueton; 2 | 3 | import java.io.File; 4 | import java.io.FileOutputStream; 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | 8 | import android.content.Context; 9 | import android.os.Environment; 10 | import android.telephony.TelephonyManager; 11 | import android.util.Log; 12 | import ar.fsadosky.marvintoqueton.hooks.*; 13 | import ar.fsadosky.marvintoqueton.privacyhooks.ContactsHelper; 14 | import ar.fsadosky.marvintoqueton.privacyhooks.DeviceDataHook; 15 | import ar.fsadosky.marvintoqueton.privacyhooks.LocationHook; 16 | import ar.fsadosky.marvintoqueton.privacyhooks.WifiHook; 17 | 18 | public class Main { 19 | 20 | static void initialize() { 21 | 22 | // gui fuzzer hooks 23 | (new EditTextHook()).hook(); 24 | (new DatePickerHook()).hook(); 25 | (new TimePickerHook()).hook(); 26 | (new ToggleButtonHook()).hook(); 27 | (new SpinnerHook()).hook(); 28 | (new ButtonHook()).hook(); 29 | (new RadioGroupHook()).hook(); 30 | (new SearchViewHook()).hook(); 31 | (new CheckboxHook()).hook(); 32 | (new AdapterViewHook()).hook(); 33 | (new ViewGroupHook()).hook(); 34 | (new ViewHook()).hook(); 35 | 36 | // privacy Hooks 37 | (new WifiHook()).hook(); 38 | (new DeviceDataHook()).hook(); 39 | (new LocationHook()).hook(); 40 | } 41 | 42 | private static void CopyJsontoSDCard(Context c) throws IOException { 43 | 44 | File dir = Environment.getExternalStorageDirectory(); 45 | InputStream in = c.getAssets().open("privacy.json"); 46 | FileOutputStream out = new FileOutputStream(dir.getAbsolutePath()+"/privacy.json"); 47 | byte[] buff = new byte[1024]; 48 | int read = 0; 49 | try { 50 | while ((read = in.read(buff)) > 0) { 51 | out.write(buff, 0, read); 52 | } 53 | } finally { 54 | in.close(); 55 | out.close(); 56 | } 57 | } 58 | 59 | public static void doOnceWhenInstalled(Context context) { 60 | 61 | ContactsHelper.AddDummyContacts(context); 62 | try { 63 | Main.CopyJsontoSDCard(context); 64 | } catch (IOException e) { 65 | e.printStackTrace(); 66 | } 67 | } 68 | } -------------------------------------------------------------------------------- /src/ar/fsadosky/marvintoqueton/MainActivity.java: -------------------------------------------------------------------------------- 1 | package ar.fsadosky.marvintoqueton; 2 | 3 | import android.os.Bundle; 4 | import android.app.Activity; 5 | import android.view.Menu; 6 | 7 | public class MainActivity extends Activity { 8 | 9 | @Override 10 | protected void onCreate(Bundle savedInstanceState) { 11 | super.onCreate(savedInstanceState); 12 | setContentView(R.layout.activity_main); 13 | Main.doOnceWhenInstalled(this); 14 | } 15 | 16 | @Override 17 | public boolean onCreateOptionsMenu(Menu menu) { 18 | // Inflate the menu; this adds items to the action bar if it is present. 19 | getMenuInflater().inflate(R.menu.main, menu); 20 | return true; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/ar/fsadosky/marvintoqueton/MessageHandler.java: -------------------------------------------------------------------------------- 1 | package ar.fsadosky.marvintoqueton; 2 | 3 | 4 | import android.content.Context; 5 | import android.os.Handler; 6 | import android.os.Looper; 7 | import android.os.Message; 8 | import android.util.Log; 9 | import android.view.View; 10 | import ar.fsadosky.marvintoqueton.hooks.Hook; 11 | 12 | public class MessageHandler { 13 | public static Handler handler; 14 | //Last used context in a view, used to start another activity 15 | public static Context context; 16 | //is third party app 17 | public static boolean third_party = false; 18 | 19 | 20 | public static void sendMessage(Object object, int code, long delayMillis) { 21 | Message msg = MessageHandler.getHandler().obtainMessage(code, object); 22 | MessageHandler.getHandler().sendMessageDelayed(msg, delayMillis); 23 | } 24 | 25 | public static Handler getHandler() { 26 | if (handler == null) { 27 | initMessageHandler(); 28 | } 29 | return handler; 30 | } 31 | 32 | public static void initMessageHandler() { 33 | if (handler == null) { 34 | Log.d("DEBUG", "initializating handler"); 35 | handler = new Handler(Looper.getMainLooper()) { 36 | @Override 37 | public void handleMessage(Message inputMessage) { 38 | try { 39 | switch (inputMessage.what) { 40 | /*case Hook.CLEAN_SERVED_VIEWS_TIMER: 41 | Hook.already_served_views.clear(); 42 | //resend message again 43 | Utils.sendMessageToClearServedViews(); 44 | break;*/ 45 | case Hook.UPDATEVIEW: 46 | UpdateViewTask viewTask = (UpdateViewTask) inputMessage.obj; 47 | //allows changing activity 48 | if(context == null){ 49 | //init if it's third_party 50 | third_party = Utils.isThirdParty(viewTask.view.getContext(), viewTask.view.getContext().getPackageName()); 51 | } 52 | //updating last used context 53 | MessageHandler.context = viewTask.view.getContext(); 54 | 55 | Log.d("DEBUG", "ID: " + viewTask.view.getId()); 56 | Log.d("DEBUG", "Class: " 57 | + viewTask.view.getClass().getName()); 58 | Log.d("DEBUG", 59 | "getVisibility: " 60 | + viewTask.view.getVisibility()); 61 | // if was dettached, do not process it 62 | if (Hook.dettached_views.contains(viewTask.view)) { 63 | Hook.dettached_views.remove(viewTask.view); 64 | Log.d("DEBUG", 65 | "stopped processing detached view"); 66 | return; 67 | } 68 | /* 69 | Log.d("DEBUG","Served views size"+Hook.already_served_views.size()); 70 | Log.d("DEBUG","Served views "+Arrays.toString(Hook.already_served_views.toArray())); 71 | if(Hook.already_served_views.contains(viewTask.view)){ 72 | //there appears to be multiple instances of the same 73 | //view, since served_already is refreshed every 74 | //min delay so stop processing this update 75 | Log.d("DEBUG", 76 | "view was served before MIN delay"); 77 | return; 78 | } 79 | else{ 80 | //marking as served 81 | Hook.already_served_views.add(viewTask.view); 82 | }*/ 83 | 84 | // If set to repeat, send message again 85 | if (viewTask.hook.updateView(viewTask.view) && viewTask.repeat) { 86 | 87 | long newdelay = 0; 88 | // long delay for background objects 89 | if (viewTask.view.getVisibility() != View.VISIBLE) { 90 | newdelay = Utils.getRandomWaitForEvent() * 5; 91 | } else { 92 | newdelay = Utils.getRandomWaitForEvent(); 93 | } 94 | Log.d("DEBUG", 95 | "ID delay is " + viewTask.view.getId()); 96 | Log.d("DEBUG", "new delay is " + newdelay); 97 | handler.sendMessageDelayed( 98 | Message.obtain(inputMessage), 99 | newdelay); 100 | } 101 | break; 102 | case Hook.CHANGE_ACTIVITY: 103 | Log.d("DEBUG", "Changing activity "); 104 | //only for third_parties 105 | if( MessageHandler.context != null && third_party){ 106 | Log.d("DEBUG", "Changing activity "); 107 | Utils.changeToRandomActivity(MessageHandler.context); 108 | } 109 | handler.sendMessageDelayed( 110 | Message.obtain(inputMessage), 111 | Utils.MIN_DELAY_FOR_EVENT * 5); 112 | break; 113 | } 114 | } catch (Exception e) { 115 | Log.d("DEBUG", "Ignoring exceptions "); 116 | Log.d("DEBUG", Log.getStackTraceString(e)); 117 | } 118 | } 119 | 120 | }; 121 | //send message to clear served views every MIN seconds 122 | //Utils.sendMessageToClearServedViews(); 123 | //send message to change activity 124 | Utils.sendMessageToChangeActivity(); 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/ar/fsadosky/marvintoqueton/UpdateViewTask.java: -------------------------------------------------------------------------------- 1 | package ar.fsadosky.marvintoqueton; 2 | 3 | import android.view.View; 4 | import ar.fsadosky.marvintoqueton.hooks.Hook; 5 | 6 | public class UpdateViewTask{ 7 | public View view; 8 | public Hook hook; 9 | public boolean repeat = false; 10 | } 11 | -------------------------------------------------------------------------------- /src/ar/fsadosky/marvintoqueton/Utils.java: -------------------------------------------------------------------------------- 1 | package ar.fsadosky.marvintoqueton; 2 | 3 | import java.util.Arrays; 4 | import java.util.Random; 5 | 6 | import android.content.ComponentName; 7 | import android.content.Context; 8 | import android.content.Intent; 9 | import android.content.pm.ActivityInfo; 10 | import android.content.pm.ApplicationInfo; 11 | import android.content.pm.PackageInfo; 12 | import android.content.pm.PackageManager; 13 | import android.content.pm.PackageManager.NameNotFoundException; 14 | import android.util.Log; 15 | import android.view.View; 16 | import ar.fsadosky.marvintoqueton.hooks.Hook; 17 | 18 | public class Utils { 19 | 20 | public static final int MIN_DELAY_FOR_EVENT = 10000; 21 | public static final int MAX_DELAY_FOR_EVENT = 20000; 22 | public static final String ERROR = "FUZZER_ERROR"; 23 | 24 | public static boolean isThirdParty(Context context, String packageName) { 25 | PackageManager manager = context.getPackageManager(); 26 | try { 27 | return !((manager.getPackageInfo(packageName, 0).applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0); 28 | } catch (NameNotFoundException e) { 29 | return false; 30 | } 31 | } 32 | 33 | public static void sendMessageToClearServedViews() { 34 | MessageHandler.sendMessage(null, Hook.CLEAN_SERVED_VIEWS_TIMER, 35 | Utils.MIN_DELAY_FOR_EVENT); 36 | } 37 | 38 | public static void sendMessageToChangeActivity() { 39 | MessageHandler.sendMessage(null, Hook.CHANGE_ACTIVITY,Utils.MIN_DELAY_FOR_EVENT * 10); 40 | } 41 | 42 | public static void repeatAtRandomEventToUpdateView(Hook hook, View hooked, 43 | long delay) { 44 | UpdateViewTask task = new UpdateViewTask(); 45 | task.view = hooked; 46 | task.hook = hook; 47 | task.repeat = true; 48 | MessageHandler.sendMessage(task, Hook.UPDATEVIEW, delay); 49 | } 50 | 51 | public static void sendEventToUpdateView(Hook hook, View hooked, long delay) { 52 | UpdateViewTask task = new UpdateViewTask(); 53 | task.view = hooked; 54 | task.hook = hook; 55 | MessageHandler.sendMessage(task, Hook.UPDATEVIEW, delay); 56 | } 57 | 58 | public static int randInt(int Low, int High) { 59 | Random r = new Random(); 60 | int random = r.nextInt(High - Low) + Low; 61 | return random; 62 | } 63 | 64 | public static long getRandomWaitForEvent() { 65 | // get random between 500 milliseconds and 3000 (3 seconds) 66 | return randInt(MIN_DELAY_FOR_EVENT, MAX_DELAY_FOR_EVENT); 67 | } 68 | 69 | public static void changeToRandomActivity(Context context) throws NameNotFoundException { 70 | PackageManager manager = context.getPackageManager(); 71 | PackageInfo info = manager.getPackageInfo(context.getPackageName(), PackageManager.GET_ACTIVITIES); 72 | int randomIndex = Utils.randInt(0, info.activities.length); 73 | ActivityInfo activity = info.activities[randomIndex]; 74 | Intent intent = new Intent(); 75 | ComponentName name =new ComponentName(activity.applicationInfo.packageName, 76 | activity.name); 77 | intent.setComponent(name); 78 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 79 | context.startActivity(intent); 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/ar/fsadosky/marvintoqueton/hooks/AdapterViewHook.java: -------------------------------------------------------------------------------- 1 | package ar.fsadosky.marvintoqueton.hooks; 2 | 3 | import android.util.Log; 4 | import android.view.View; 5 | import android.widget.AdapterView; 6 | import ar.fsadosky.marvintoqueton.Utils; 7 | 8 | public class AdapterViewHook extends Hook { 9 | 10 | protected String getHookedClass() { 11 | return "android.widget.AdapterView"; 12 | } 13 | 14 | protected boolean getCallMultipleTimes() { 15 | return true; 16 | } 17 | 18 | @Override 19 | public boolean updateView(View view) { 20 | AdapterView adapterview = (AdapterView) view; 21 | Log.d("DEBUG", "Setting clicking in adapter view "); 22 | if (adapterview.getCount() > 0) { 23 | int randomIndex = Utils.randInt(0, adapterview.getCount()); 24 | View child = adapterview.getAdapter().getView(randomIndex, null, 25 | null); 26 | adapterview.setSelection(randomIndex); 27 | adapterview.performItemClick(child, randomIndex, 28 | adapterview.getItemIdAtPosition(randomIndex)); 29 | } 30 | view.setFocusable(false); 31 | return true; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/ar/fsadosky/marvintoqueton/hooks/ButtonHook.java: -------------------------------------------------------------------------------- 1 | package ar.fsadosky.marvintoqueton.hooks; 2 | 3 | import android.util.Log; 4 | import android.view.View; 5 | import android.widget.Button; 6 | 7 | public class ButtonHook extends Hook { 8 | 9 | public String getHookedClass() { 10 | return "android.widget.Button"; 11 | } 12 | 13 | protected boolean getCallMultipleTimes() { 14 | return true; 15 | } 16 | 17 | @Override 18 | public boolean updateView(View view) { 19 | Log.d("DEBUG", "Pressing button "); 20 | ((Button) view).performClick(); 21 | view.setFocusable(false); 22 | return true; 23 | 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/ar/fsadosky/marvintoqueton/hooks/CheckboxHook.java: -------------------------------------------------------------------------------- 1 | package ar.fsadosky.marvintoqueton.hooks; 2 | 3 | import android.util.Log; 4 | import android.view.View; 5 | import android.widget.CheckBox; 6 | 7 | public class CheckboxHook extends Hook { 8 | 9 | public String getHookedClass() { 10 | return "android.widget.CheckBox"; 11 | } 12 | 13 | protected boolean getCallMultipleTimes() { 14 | return true; 15 | } 16 | 17 | @Override 18 | public boolean updateView(View view) { 19 | CheckBox checkbox = (CheckBox) view; 20 | Log.d("DEBUG", "Setting checkbox " + !checkbox.isChecked()); 21 | checkbox.setChecked(checkbox.isChecked()); 22 | view.setFocusable(false); 23 | return true; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/ar/fsadosky/marvintoqueton/hooks/DatePickerHook.java: -------------------------------------------------------------------------------- 1 | package ar.fsadosky.marvintoqueton.hooks; 2 | 3 | import android.util.Log; 4 | import android.view.View; 5 | import android.widget.DatePicker; 6 | 7 | 8 | public class DatePickerHook extends Hook { 9 | 10 | public String getHookedClass() { 11 | return "android.widget.DatePicker"; 12 | } 13 | 14 | @Override 15 | public boolean updateView(View view) { 16 | Log.d("DEBUG", "Setting date "); 17 | ((DatePicker) view).updateDate( 18 | 1989, 1, 1); 19 | view.setFocusable(false); 20 | return true; 21 | } 22 | 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/ar/fsadosky/marvintoqueton/hooks/EditTextHook.java: -------------------------------------------------------------------------------- 1 | package ar.fsadosky.marvintoqueton.hooks; 2 | 3 | import java.util.Locale; 4 | import java.util.regex.Matcher; 5 | import java.util.regex.Pattern; 6 | 7 | import android.text.InputType; 8 | import android.util.Log; 9 | import android.view.View; 10 | import android.widget.EditText; 11 | 12 | public class EditTextHook extends Hook { 13 | private final static String[] mailKeywords = { "mail" }; 14 | private final static String[] phoneKeywords = { "cell", "phone", "mobile" }; 15 | private final static String[] passwordKeywords = { "password", "pwd", 16 | "pass", "characters" }; 17 | private final static String[] nameKeywords = { "name", "lastname", "last", 18 | "last_name" }; 19 | private final static String[] zipKeywords = { "zip", "postal" }; 20 | private static final String EMAIL_PATTERN = "^[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*@" 21 | + "[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$"; 22 | 23 | public String getHookedClass() { 24 | return "android.widget.EditText"; 25 | } 26 | 27 | static boolean looksLike(String match, String EMAIL_PATTERN) { 28 | if (match == null) 29 | return false; 30 | Pattern pattern = Pattern.compile(EMAIL_PATTERN); 31 | Matcher matcher = pattern.matcher(match); 32 | return matcher.matches(); 33 | } 34 | 35 | static boolean hasKeywords(String match, String[] keywords) { 36 | if (match == null) 37 | return false; 38 | for (String key : keywords) { 39 | if (match.toLowerCase(Locale.getDefault()).contains(key)) { 40 | return true; 41 | } 42 | } 43 | return false; 44 | } 45 | 46 | protected String getMessage(View hooked) { 47 | return getMessageFor(hooked); 48 | } 49 | 50 | public static String getMessageFor(View hooked) { 51 | String message = null; 52 | EditText textview = (EditText) hooked; 53 | 54 | String resource_id = textview.getContext().getResources() 55 | .getResourceEntryName(textview.getId()); 56 | String hint = "" + textview.getHint(); 57 | int types = textview.getInputType(); 58 | 59 | Log.d("DEBUG", "id " + textview.getId()); 60 | Log.d("DEBUG", "name " + resource_id); 61 | Log.d("DEBUG", "hint " + hint); 62 | Log.d("DEBUG", "class " + textview.getClass().getName()); 63 | 64 | if ((types & InputType.TYPE_CLASS_NUMBER) == InputType.TYPE_CLASS_NUMBER 65 | || (types & InputType.TYPE_NUMBER_FLAG_DECIMAL) == InputType.TYPE_NUMBER_FLAG_DECIMAL 66 | || (types & InputType.TYPE_NUMBER_FLAG_SIGNED) == InputType.TYPE_NUMBER_FLAG_SIGNED) { 67 | Log.d("DEBUG", "setting number"); 68 | message = "23"; 69 | } 70 | if ((types & InputType.TYPE_CLASS_TEXT) == InputType.TYPE_CLASS_TEXT) { 71 | Log.d("DEBUG", "setting text"); 72 | message = "FuzzingText"; 73 | } 74 | 75 | if ((types & InputType.TYPE_DATETIME_VARIATION_NORMAL) == InputType.TYPE_DATETIME_VARIATION_NORMAL 76 | || (types & InputType.TYPE_DATETIME_VARIATION_DATE) == InputType.TYPE_DATETIME_VARIATION_DATE) { 77 | Log.d("DEBUG", "setting date"); 78 | message = "01-02-1989"; 79 | } 80 | 81 | if ((types & InputType.TYPE_DATETIME_VARIATION_TIME) == InputType.TYPE_DATETIME_VARIATION_TIME) { 82 | Log.d("DEBUG", "setting time"); 83 | message = "00:70:07"; 84 | } 85 | 86 | if ((types & InputType.TYPE_CLASS_PHONE) == InputType.TYPE_CLASS_PHONE 87 | || hasKeywords(hint, phoneKeywords) 88 | || hasKeywords(resource_id, phoneKeywords)) { 89 | Log.d("DEBUG", "setting phone"); 90 | message = "1112341234"; 91 | } 92 | 93 | if ((types & InputType.TYPE_TEXT_VARIATION_PERSON_NAME) == InputType.TYPE_TEXT_VARIATION_PERSON_NAME 94 | || hasKeywords(hint, nameKeywords) 95 | || hasKeywords(resource_id, nameKeywords)) { 96 | Log.d("DEBUG", "setting name"); 97 | message = "NameFuzzing"; 98 | } 99 | if ((types & InputType.TYPE_TEXT_VARIATION_POSTAL_ADDRESS) == InputType.TYPE_TEXT_VARIATION_POSTAL_ADDRESS 100 | || hasKeywords(hint, zipKeywords) 101 | || hasKeywords(resource_id, zipKeywords)) { 102 | Log.d("DEBUG", "setting postal code"); 103 | message = "90210"; 104 | } 105 | if ((types & InputType.TYPE_TEXT_VARIATION_URI) == InputType.TYPE_TEXT_VARIATION_URI) { 106 | Log.d("DEBUG", "setting URI"); 107 | message = "http://www.fundacionsadosky.org.ar"; 108 | } 109 | if ((types & InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS) == InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS 110 | || (types & InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS) == InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS 111 | || hasKeywords(hint, mailKeywords) 112 | || hasKeywords(resource_id, mailKeywords) 113 | || looksLike(hint, EMAIL_PATTERN)) { 114 | message = "fakeemailandroid@gmail.com"; 115 | } 116 | 117 | if ((types & InputType.TYPE_NUMBER_VARIATION_PASSWORD) == InputType.TYPE_NUMBER_VARIATION_PASSWORD) { 118 | Log.d("DEBUG", "setting number password"); 119 | message = "007007"; 120 | } else if ((types & InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) == InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD 121 | || (types & InputType.TYPE_TEXT_VARIATION_PASSWORD) == InputType.TYPE_TEXT_VARIATION_PASSWORD 122 | || (types & InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD) == InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD 123 | || hasKeywords(hint, passwordKeywords) 124 | || hasKeywords(resource_id, passwordKeywords)) { 125 | Log.d("DEBUG", "setting password"); 126 | message = "s3cr3tpass"; 127 | } 128 | 129 | return message; 130 | 131 | } 132 | 133 | @Override 134 | public boolean updateView(View view) { 135 | Log.d("DEBUG", "Setting edittext " + EditTextHook.getMessageFor(view)); 136 | ((EditText) view).setText(EditTextHook.getMessageFor(view)); 137 | view.setFocusable(false); 138 | return true; 139 | 140 | } 141 | 142 | } 143 | -------------------------------------------------------------------------------- /src/ar/fsadosky/marvintoqueton/hooks/Hook.java: -------------------------------------------------------------------------------- 1 | package ar.fsadosky.marvintoqueton.hooks; 2 | 3 | import java.lang.reflect.Constructor; 4 | import java.util.HashSet; 5 | import java.util.Set; 6 | 7 | import android.content.Context; 8 | import android.util.AttributeSet; 9 | import android.util.Log; 10 | import android.view.View; 11 | import android.view.View.OnAttachStateChangeListener; 12 | import android.widget.AdapterView; 13 | import android.widget.Button; 14 | import android.widget.CheckBox; 15 | import android.widget.DatePicker; 16 | import android.widget.EditText; 17 | import android.widget.RadioGroup; 18 | import android.widget.Spinner; 19 | import android.widget.TimePicker; 20 | import android.widget.ToggleButton; 21 | import ar.fsadosky.marvintoqueton.Utils; 22 | 23 | import com.saurik.substrate.MS; 24 | 25 | public abstract class Hook { 26 | final static Class hooked[] = { Button.class, CheckBox.class, 27 | EditText.class, RadioGroup.class, Spinner.class, TimePicker.class, 28 | DatePicker.class, ToggleButton.class, AdapterView.class , ViewGroupHook.class }; 29 | 30 | public static final int UPDATEVIEW = 0; 31 | public static final int CLEAN_SERVED_VIEWS_TIMER = 1; 32 | public static final int CHANGE_ACTIVITY = 2; 33 | 34 | public static Set dettached_views = new HashSet(); 35 | //public static Set already_served_views = new HashSet(); 36 | 37 | public abstract boolean updateView(View view); 38 | 39 | public void hook() { 40 | MS.hookClassLoad(getHookedClass(), new MS.ClassLoadHook() { 41 | public void classLoaded(final Class class_hooked) { 42 | if (getConstructor() != null) { 43 | Log.d("DEBUG", "hooking " + class_hooked.getName()); 44 | MS.hookMethod(class_hooked, getConstructor(), 45 | new MS.MethodAlteration() { 46 | public Object invoked(Object hooked, 47 | Object... args) throws Throwable { 48 | Object o = invoke(hooked, args); 49 | Context c = (Context) args[0]; 50 | if (Utils.isThirdParty(c, 51 | c.getPackageName()) && (checkHook((View) hooked))) { 52 | if (getCallMultipleTimes()) 53 | Utils.repeatAtRandomEventToUpdateView(Hook.this, 54 | (View) hooked, getDelay()); 55 | else 56 | Utils.sendEventToUpdateView(Hook.this,(View) hooked,getDelay()); 57 | ((View) hooked).addOnAttachStateChangeListener(new OnAttachStateChangeListener() { 58 | 59 | @Override 60 | public void onViewDetachedFromWindow(View v) { 61 | Log.d("DEBUG","detached window, when obtaining it in handler it will be removed"); 62 | Hook.dettached_views .add(v); 63 | } 64 | 65 | @Override 66 | public void onViewAttachedToWindow( 67 | View v) {} 68 | }); 69 | } 70 | 71 | return o; 72 | } 73 | 74 | }); 75 | } 76 | 77 | } 78 | 79 | }); 80 | } 81 | 82 | protected long getDelay() { 83 | return Utils.getRandomWaitForEvent(); 84 | } 85 | 86 | protected String getHookedClass() { 87 | Log.d("DEBUG", "calling empty"); 88 | return ""; 89 | } 90 | 91 | protected boolean checkHook(View view) { 92 | return true; 93 | } 94 | 95 | protected boolean getCallMultipleTimes() { 96 | return false; 97 | } 98 | 99 | protected Constructor getConstructor() { 100 | Constructor constructor = null; 101 | try { 102 | constructor = Class.forName(getHookedClass()) 103 | .getDeclaredConstructor(Context.class, AttributeSet.class, 104 | int.class); 105 | } catch (Exception e) { 106 | Log.d("DEBUG", Log.getStackTraceString(e)); 107 | } 108 | return constructor; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/ar/fsadosky/marvintoqueton/hooks/RadioGroupHook.java: -------------------------------------------------------------------------------- 1 | package ar.fsadosky.marvintoqueton.hooks; 2 | 3 | import java.lang.reflect.Constructor; 4 | 5 | import android.content.Context; 6 | import android.util.AttributeSet; 7 | import android.util.Log; 8 | import android.view.View; 9 | import android.widget.RadioButton; 10 | import android.widget.RadioGroup; 11 | import ar.fsadosky.marvintoqueton.Utils; 12 | 13 | public class RadioGroupHook extends Hook { 14 | 15 | public String getHookedClass() { 16 | return "android.widget.RadioGroup"; 17 | } 18 | 19 | protected boolean getCallMultipleTimes() { 20 | return true; 21 | } 22 | 23 | protected Constructor getConstructor() { 24 | Constructor constructor = null; 25 | try { 26 | constructor = Class.forName(getHookedClass()) 27 | .getDeclaredConstructor(Context.class, AttributeSet.class); 28 | } catch (Exception e) { 29 | Log.d("DEBUG", Log.getStackTraceString(e)); 30 | } 31 | return constructor; 32 | } 33 | 34 | @Override 35 | public boolean updateView(View view) { 36 | RadioGroup radioGroup = ((RadioGroup) view); 37 | if (radioGroup.getChildCount() > 0) { 38 | int randomIndex = Utils.randInt(0, radioGroup.getChildCount()); 39 | Log.d("DEBUG", "Setting radioGroup index " + randomIndex); 40 | ((RadioButton) radioGroup.getChildAt(randomIndex)).setChecked(true); 41 | } 42 | radioGroup.setFocusable(false); 43 | return true; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/ar/fsadosky/marvintoqueton/hooks/SearchViewHook.java: -------------------------------------------------------------------------------- 1 | package ar.fsadosky.marvintoqueton.hooks; 2 | 3 | import java.lang.reflect.Constructor; 4 | 5 | import android.content.Context; 6 | import android.util.AttributeSet; 7 | import android.util.Log; 8 | import android.view.View; 9 | import android.widget.SearchView; 10 | import ar.fsadosky.marvintoqueton.Utils; 11 | 12 | public class SearchViewHook extends Hook { 13 | final private static String searchKeywords[] = { "app", "Android", 14 | "application", "phone" }; 15 | 16 | public String getHookedClass() { 17 | return "android.widget.SearchView"; 18 | } 19 | 20 | protected boolean getCallMultipleTimes() { 21 | return true; 22 | } 23 | 24 | public static String getQueryFor(View view) { 25 | return searchKeywords[Utils.randInt(0, searchKeywords.length)]; 26 | } 27 | 28 | protected long getDelay() { 29 | return Utils.getRandomWaitForEvent() * 5; 30 | } 31 | 32 | protected Constructor getConstructor() { 33 | Constructor constructor = null; 34 | try { 35 | constructor = Class.forName(getHookedClass()) 36 | .getDeclaredConstructor(Context.class, AttributeSet.class); 37 | } catch (Exception e) { 38 | Log.d("DEBUG", Log.getStackTraceString(e)); 39 | } 40 | return constructor; 41 | } 42 | 43 | @Override 44 | public boolean updateView(View view) { 45 | SearchView searchView = ((SearchView) view); 46 | Log.d("DEBUG", "Performing search "); 47 | searchView.setQuery(SearchViewHook.getQueryFor(searchView), true); 48 | view.setFocusable(false); 49 | return true; 50 | 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/ar/fsadosky/marvintoqueton/hooks/SpinnerHook.java: -------------------------------------------------------------------------------- 1 | package ar.fsadosky.marvintoqueton.hooks; 2 | 3 | import android.util.Log; 4 | import android.view.View; 5 | import android.widget.Spinner; 6 | import ar.fsadosky.marvintoqueton.Utils; 7 | 8 | public class SpinnerHook extends Hook { 9 | 10 | public String getHookedClass() { 11 | return "android.widget.Spinner"; 12 | } 13 | 14 | protected boolean getCallMultipleTimes() { 15 | return true; 16 | } 17 | 18 | @Override 19 | public boolean updateView(View view) { 20 | Spinner spinner = (Spinner) view; 21 | int randomIndex = Utils.randInt(0, spinner.getChildCount()); 22 | Log.d("DEBUG", "Setting radioGroup index " + randomIndex); 23 | spinner.setSelection(randomIndex); 24 | view.setFocusable(false); 25 | return true; 26 | 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/ar/fsadosky/marvintoqueton/hooks/TimePickerHook.java: -------------------------------------------------------------------------------- 1 | package ar.fsadosky.marvintoqueton.hooks; 2 | 3 | import android.util.Log; 4 | import android.view.View; 5 | import android.widget.TimePicker; 6 | 7 | public class TimePickerHook extends Hook { 8 | public String getHookedClass() { 9 | return "android.widget.TimePicker"; 10 | } 11 | 12 | @Override 13 | public boolean updateView(View view) { 14 | TimePicker timePicker = ((TimePicker) view); 15 | Log.d("DEBUG", "Setting Timepicker"); 16 | timePicker.setCurrentHour(007); 17 | timePicker.setCurrentMinute(007); 18 | view.setFocusable(false); 19 | return true; 20 | 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/ar/fsadosky/marvintoqueton/hooks/ToggleButtonHook.java: -------------------------------------------------------------------------------- 1 | package ar.fsadosky.marvintoqueton.hooks; 2 | 3 | import android.util.Log; 4 | import android.view.View; 5 | import android.widget.ToggleButton; 6 | 7 | public class ToggleButtonHook extends Hook { 8 | 9 | public String getHookedClass() { 10 | return "android.widget.ToggleButton"; 11 | } 12 | 13 | protected boolean getCallMultipleTimes() { 14 | return true; 15 | } 16 | 17 | @Override 18 | public boolean updateView(View view) { 19 | ToggleButton toggle = (ToggleButton) view; 20 | Log.d("DEBUG", "Setting ToggleButton to " + !toggle.isChecked()); 21 | toggle.setChecked(!toggle.isChecked()); 22 | view.setFocusable(false); 23 | return true; 24 | 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/ar/fsadosky/marvintoqueton/hooks/ViewGroupHook.java: -------------------------------------------------------------------------------- 1 | package ar.fsadosky.marvintoqueton.hooks; 2 | 3 | import android.util.Log; 4 | import android.view.View; 5 | import android.view.ViewGroup; 6 | import ar.fsadosky.marvintoqueton.Utils; 7 | 8 | public class ViewGroupHook extends Hook { 9 | 10 | protected String getHookedClass() { 11 | return "android.view.ViewGroup"; 12 | } 13 | 14 | protected boolean getCallMultipleTimes() { 15 | return true; 16 | } 17 | 18 | protected long getDelay() { 19 | return Utils.getRandomWaitForEvent() * 3; 20 | } 21 | 22 | @Override 23 | public boolean updateView(View view) { 24 | int childCount = ((ViewGroup) view).getChildCount(); 25 | Log.d("DEBUG", "child count is " + childCount); 26 | if (childCount > 0) { 27 | int randomIndex = Utils.randInt(0, childCount); 28 | View child = ((ViewGroup) view).getChildAt(randomIndex); 29 | int x = child.getHeight(); 30 | int y = child.getWidth(); 31 | ((ViewGroup) view).requestChildFocus(child, child); 32 | Log.d("DEBUG", "scrolling view to " + x + " " + y); 33 | } 34 | if (view.isClickable() && view.isLongClickable()) { 35 | Log.d("DEBUG", "Clicking view "); 36 | int random = Utils.randInt(0, 3); 37 | // 2 out of 3 perform simple click 38 | if (random % 2 == 0) 39 | view.performClick(); 40 | else 41 | view.performLongClick(); 42 | } else if (view.isClickable()) { 43 | Log.d("DEBUG", "Clicking view "); 44 | view.performClick(); 45 | } else if (view.isLongClickable()) { 46 | Log.d("DEBUG", "Clicking view "); 47 | view.performLongClick(); 48 | } 49 | return true; 50 | 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/ar/fsadosky/marvintoqueton/hooks/ViewHook.java: -------------------------------------------------------------------------------- 1 | package ar.fsadosky.marvintoqueton.hooks; 2 | 3 | import android.util.Log; 4 | import android.view.View; 5 | import android.view.ViewGroup; 6 | import ar.fsadosky.marvintoqueton.Utils; 7 | 8 | public class ViewHook extends Hook { 9 | 10 | protected String getHookedClass() { 11 | return "android.view.View"; 12 | } 13 | 14 | protected boolean checkHook(View view) { 15 | for (Class c : hooked) { 16 | if (view.getClass() == c) 17 | return false; 18 | } 19 | return true; 20 | } 21 | 22 | protected boolean getCallMultipleTimes() { 23 | return true; 24 | } 25 | 26 | protected long getDelay() { 27 | return Utils.getRandomWaitForEvent() * 3; 28 | } 29 | 30 | @Override 31 | public boolean updateView(View view) { 32 | if (view.isClickable() && view.isLongClickable()) { 33 | Log.d("DEBUG", "Clicking view "); 34 | int random = Utils.randInt(0, 3); 35 | // 2 out of 3 perform simple click 36 | if (random % 2 == 0) 37 | view.performClick(); 38 | else 39 | view.performLongClick(); 40 | } else if (view.isClickable()) { 41 | Log.d("DEBUG", "Clicking view "); 42 | view.performClick(); 43 | } else if (view.isLongClickable()) { 44 | Log.d("DEBUG", "Clicking view "); 45 | view.performLongClick(); 46 | } else { 47 | // do not call back message 48 | return false; 49 | } 50 | return true; 51 | 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/ar/fsadosky/marvintoqueton/privacyhooks/ContactsHelper.java: -------------------------------------------------------------------------------- 1 | package ar.fsadosky.marvintoqueton.privacyhooks; 2 | 3 | import java.util.ArrayList; 4 | 5 | import android.content.ContentProviderOperation; 6 | import android.content.ContentProviderResult; 7 | import android.content.Context; 8 | import android.content.OperationApplicationException; 9 | import android.os.RemoteException; 10 | import android.provider.ContactsContract.RawContacts; 11 | import android.provider.ContactsContract; 12 | import android.provider.ContactsContract.CommonDataKinds.Phone; 13 | import android.provider.ContactsContract.CommonDataKinds.StructuredName; 14 | import android.provider.ContactsContract.Contacts.Data; 15 | 16 | public class ContactsHelper { 17 | 18 | public static void AddDummyContacts(Context c) { 19 | ArrayList ops = new ArrayList(); 20 | int rawContactInsertIndex = ops.size(); 21 | 22 | ops.add(ContentProviderOperation.newInsert(RawContacts.CONTENT_URI) 23 | .withValue(RawContacts.ACCOUNT_TYPE, null) 24 | .withValue(RawContacts.ACCOUNT_NAME, null).build()); 25 | 26 | // Phone Number 27 | ops.add(ContentProviderOperation 28 | .newInsert(ContactsContract.Data.CONTENT_URI) 29 | .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 30 | rawContactInsertIndex) 31 | .withValue(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE) 32 | .withValue(Phone.NUMBER, "1107060504") 33 | .withValue(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE) 34 | .withValue(Phone.TYPE, "1").build()); 35 | 36 | // Display name/Contact name 37 | ops.add(ContentProviderOperation 38 | .newInsert(ContactsContract.Data.CONTENT_URI) 39 | .withValueBackReference(Data.RAW_CONTACT_ID, 40 | rawContactInsertIndex) 41 | .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE) 42 | .withValue(StructuredName.DISPLAY_NAME, "C0ntactFuzz").build()); 43 | try { 44 | ContentProviderResult[] res = c.getContentResolver().applyBatch( 45 | ContactsContract.AUTHORITY, ops); 46 | } catch (RemoteException e) { 47 | // TODO Auto-generated catch block 48 | e.printStackTrace(); 49 | } catch (OperationApplicationException e) { 50 | // TODO Auto-generated catch block 51 | e.printStackTrace(); 52 | } 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/ar/fsadosky/marvintoqueton/privacyhooks/DeviceDataHook.java: -------------------------------------------------------------------------------- 1 | package ar.fsadosky.marvintoqueton.privacyhooks; 2 | 3 | public class DeviceDataHook extends PrivacyHook { 4 | 5 | public void hook() { 6 | 7 | // mising hook 8 | 9 | // get SimOperatorName 10 | // getNetworkOperatorName 11 | // getNetworkOperator 12 | // getSIMOperator 13 | Class[] params = new Class[0]; 14 | String telephonyManager = "android.telephony.TelephonyManager"; 15 | hookAndSaveReturnValue(telephonyManager, "getSimOperatorName", params); 16 | hookAndSaveReturnValue(telephonyManager, "getSimOperator", params); 17 | hookAndSaveReturnValue(telephonyManager, "getNetworkOperator", params); 18 | hookAndSaveReturnValue(telephonyManager, "getNetworkOperatorName", params); 19 | 20 | String gsmPhone = "com.android.internal.telephony.gsm.GSMPhone"; 21 | hookAndSaveReturnValue(gsmPhone, "getDeviceId", params); 22 | hookAndSaveReturnValue(gsmPhone, "getImei", params); 23 | hookAndSaveReturnValue(gsmPhone, "getSubscriberId", params); 24 | hookAndSaveReturnValue(gsmPhone, "getLine1Number", params); 25 | 26 | String CDMAPhone = "com.android.internal.telephony.gsm.CDMAPhone"; 27 | hookAndSaveReturnValue(CDMAPhone, "getDeviceId", params); 28 | hookAndSaveReturnValue(CDMAPhone, "getMeid", params); 29 | hookAndSaveReturnValue(CDMAPhone, "getSubscriberId", params); 30 | hookAndSaveReturnValue(CDMAPhone, "getLine1Number", params); 31 | 32 | hookAndSaveReturnValue("com.android.internal.telephony.PhoneBase", 33 | "getIccSerialNumber", params); 34 | 35 | } 36 | 37 | @Override 38 | protected Object convertFromProfile(String clazz, String method, String value) { 39 | return value; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/ar/fsadosky/marvintoqueton/privacyhooks/FakeLocationListener.java: -------------------------------------------------------------------------------- 1 | package ar.fsadosky.marvintoqueton.privacyhooks; 2 | 3 | import android.location.Location; 4 | import android.location.LocationListener; 5 | import android.os.Bundle; 6 | 7 | public class FakeLocationListener implements LocationListener { 8 | 9 | private Location fakeLocation; 10 | private LocationListener appListener; 11 | 12 | public void setListener(LocationListener p) { 13 | appListener = p; 14 | } 15 | 16 | public void setLocation(Location l) { 17 | fakeLocation = l; 18 | } 19 | 20 | @Override 21 | public void onLocationChanged(Location location) { 22 | appListener.onLocationChanged(fakeLocation); 23 | } 24 | 25 | @Override 26 | public void onProviderDisabled(String provider) { 27 | appListener.onProviderDisabled(provider); 28 | 29 | } 30 | 31 | @Override 32 | public void onProviderEnabled(String provider) { 33 | appListener.onProviderEnabled(provider); 34 | 35 | } 36 | 37 | @Override 38 | public void onStatusChanged(String provider, int status, Bundle extras) { 39 | appListener.onStatusChanged(provider, status, extras); 40 | 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/ar/fsadosky/marvintoqueton/privacyhooks/LocationHook.java: -------------------------------------------------------------------------------- 1 | package ar.fsadosky.marvintoqueton.privacyhooks; 2 | 3 | import java.lang.reflect.Method; 4 | 5 | import android.app.PendingIntent; 6 | import android.location.Location; 7 | import android.location.LocationListener; 8 | import android.location.LocationManager; 9 | 10 | import android.os.Looper; 11 | import android.util.Log; 12 | 13 | import com.saurik.substrate.MS; 14 | 15 | public class LocationHook extends PrivacyHook { 16 | 17 | public void hookgetLastKnownLocation() { 18 | Class[] params = new Class[1]; 19 | params[0] = String.class; 20 | hookAndSaveReturnValue("android.location.LocationManager", 21 | "getLastKnownLocation", params); 22 | } 23 | 24 | @Override 25 | protected Object convertFromProfile(String clazz, String method, 26 | String value) { 27 | if (method.equals("getLastKnownLocation")) { 28 | return getLocationIn(Double.parseDouble(value.split(",")[0]), 29 | Double.parseDouble(value.split(",")[1]), ""); 30 | } 31 | return null; 32 | } 33 | 34 | private static FakeLocationListener fakeListener; 35 | 36 | public void hook() { 37 | hookgetLastKnownLocation(); 38 | 39 | MS.hookClassLoad("android.location.LocationManager", 40 | new MS.ClassLoadHook() { 41 | public void classLoaded(Class _clazz) { 42 | fakeListener = new FakeLocationListener(); 43 | hookRequestUpdates(); 44 | } 45 | }); 46 | 47 | } 48 | 49 | protected static Location getLocationIn(double latitude, double longitude, 50 | String provider) { 51 | Location location = new Location(provider); 52 | location.setLatitude(latitude); 53 | location.setLongitude(longitude); 54 | location.setAltitude(0); 55 | location.setAccuracy(0.2F); 56 | location.setTime(System.currentTimeMillis()); 57 | return location; 58 | } 59 | 60 | private void hookRequestUpdates() { 61 | Method method = null; 62 | Class locationManager = null; 63 | try { 64 | locationManager = Class.forName("android.location.LocationManager"); 65 | Class locationRequest = Class 66 | .forName("android.location.LocationRequest"); 67 | Class[] params = { locationRequest, LocationListener.class, 68 | Looper.class, PendingIntent.class }; 69 | method = locationManager.getDeclaredMethod( 70 | "requestLocationUpdates", params); 71 | } catch (Exception e) { 72 | Log.d(Utils.ERROR, "No such method requestLocationUpdates"); 73 | } 74 | 75 | if (method != null) { 76 | MS.hookMethod(locationManager, method, 77 | new MS.MethodAlteration() { 78 | public Void invoked(final LocationManager hooked, 79 | final Object... args) throws Throwable { 80 | 81 | try { 82 | String value = readValueFromProfile( 83 | "android.location.LocationManager", 84 | "requestLocationUpdates"); 85 | Location location = getLocationIn( 86 | Double.parseDouble(value.split(",")[0]), 87 | Double.parseDouble(value.split(",")[1]), 88 | ""); 89 | 90 | LocationListener listener = (LocationListener) args[5]; 91 | fakeListener.setListener(listener); 92 | fakeListener.setLocation(location); 93 | args[5] = fakeListener; 94 | } catch (Exception e) { 95 | try { 96 | // TODO: we are not doing anything in 97 | // this case 98 | Log.d(Utils.DEBUG, 99 | "_requestUpdates, ASA"); 100 | //PendingIntent intent = (PendingIntent) args[5]; 101 | } catch (Exception e2) { 102 | Log.d(Utils.ERROR, 103 | "The argument should be LocationListener or PendingIntent"); 104 | } 105 | } 106 | 107 | return invoke(hooked, args); 108 | } 109 | 110 | }); 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/ar/fsadosky/marvintoqueton/privacyhooks/PrivacyHook.java: -------------------------------------------------------------------------------- 1 | package ar.fsadosky.marvintoqueton.privacyhooks; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.lang.reflect.Method; 6 | import java.nio.MappedByteBuffer; 7 | import java.nio.channels.FileChannel; 8 | import java.nio.charset.Charset; 9 | 10 | import org.json.JSONObject; 11 | 12 | import android.os.Environment; 13 | import android.util.Log; 14 | import com.saurik.substrate.MS; 15 | 16 | public abstract class PrivacyHook { 17 | protected static JSONObject privacyValues; 18 | 19 | protected static Method getMethod(String clazz, String method, 20 | Class[] params) { 21 | try { 22 | return Class.forName(clazz).getDeclaredMethod(method, params); 23 | } catch (NoSuchMethodException e) { 24 | e.printStackTrace(); 25 | } catch (ClassNotFoundException e) { 26 | e.printStackTrace(); 27 | } 28 | return null; 29 | } 30 | 31 | protected void loadJsonFromFile() { 32 | try { 33 | File dir = Environment.getExternalStorageDirectory(); 34 | File jsonFile = new File(dir, "privacy.json"); 35 | FileInputStream stream = new FileInputStream(jsonFile); 36 | String jString = null; 37 | FileChannel fc = stream.getChannel(); 38 | MappedByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, 39 | fc.size()); 40 | /* Instead of using default, pass in a decoder. */ 41 | jString = Charset.defaultCharset().decode(bb).toString(); 42 | 43 | privacyValues = new JSONObject(jString); 44 | if (stream != null) 45 | stream.close(); 46 | } catch (Exception e) { 47 | e.printStackTrace(); 48 | } 49 | } 50 | 51 | protected String readValueFromProfile(String clazz, String method) { 52 | if (privacyValues == null) { 53 | // init on first time 54 | loadJsonFromFile(); 55 | } 56 | // read json from sdcard 57 | /* 58 | * format { class1 : method1 : value, method2 : value, class2 59 | */ 60 | try { 61 | 62 | return privacyValues.getJSONObject(clazz).getString(method); 63 | } catch (Exception e) { 64 | e.printStackTrace(); 65 | } 66 | return ""; 67 | } 68 | 69 | protected abstract Object convertFromProfile(String clazz, String method, 70 | String value); 71 | 72 | protected void hookAndSaveReturnValue(final String clazz, 73 | final String methodName, final Class[] params) { 74 | MS.hookClassLoad(clazz, new MS.ClassLoadHook() { 75 | public void classLoaded(Class clazzLoaded) { 76 | Method method; 77 | try { 78 | method = clazzLoaded.getDeclaredMethod(methodName, params); 79 | } catch (NoSuchMethodException e) { 80 | Log.d(Utils.ERROR, Log.getStackTraceString(e)); 81 | method = null; 82 | } 83 | 84 | if (method != null) { 85 | MS.hookMethod(clazzLoaded, method, 86 | new MS.MethodAlteration() { 87 | public Object invoked(final Object hooked, 88 | final Object... args) throws Throwable { 89 | Object result = invoke(hooked, args); 90 | 91 | if (result == null) 92 | return null; 93 | 94 | Object returned_object = null; 95 | 96 | try { 97 | returned_object = convertFromProfile( 98 | clazz, 99 | methodName, 100 | readValueFromProfile(clazz, 101 | methodName)); 102 | } catch (Exception e) { 103 | Log.d("DEBUG", 104 | "Probably booting, return null as a fallback"); 105 | } 106 | // Log.d("DEBUG", "class:" + clazz); 107 | // Log.d("DEBUG", "method:" + methodName); 108 | // Log.d("DEBUG", "value:" + 109 | // result.toString()); 110 | 111 | return returned_object; 112 | } 113 | }); 114 | 115 | } 116 | } 117 | }); 118 | } 119 | 120 | } 121 | -------------------------------------------------------------------------------- /src/ar/fsadosky/marvintoqueton/privacyhooks/Utils.java: -------------------------------------------------------------------------------- 1 | package ar.fsadosky.marvintoqueton.privacyhooks; 2 | 3 | public class Utils { 4 | 5 | protected static final String ERROR = "FUZZER_ERROR"; 6 | protected static final String DEBUG = "FUZZER_DEBUG"; 7 | 8 | public static String getFormatedIpFromIp(Integer ipAddress) { 9 | return String.format("%d.%d.%d.%d", (ipAddress & 0xff), 10 | (ipAddress >> 8 & 0xff), (ipAddress >> 16 & 0xff), 11 | (ipAddress >> 24 & 0xff)); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/ar/fsadosky/marvintoqueton/privacyhooks/WifiHook.java: -------------------------------------------------------------------------------- 1 | package ar.fsadosky.marvintoqueton.privacyhooks; 2 | 3 | import android.content.Context; 4 | //import ar.fsadosky.fuzzinghelper.Utils; 5 | import ar.fsadosky.marvintoqueton.privacyhooks.Utils; 6 | 7 | import com.saurik.substrate.MS; 8 | 9 | public class WifiHook extends PrivacyHook { 10 | 11 | protected void hookGetDefaultIP() { 12 | Class[] params = new Class[1]; 13 | params[0] = Context.class; 14 | hookAndSaveReturnValue("com.android.settings.Utils", 15 | "getWifiIpAddresses", params); 16 | } 17 | 18 | public void hook() { 19 | hookGetDefaultIP(); 20 | hookUtilsGetDefaultWifiIpAddresses(); 21 | hookWifiConfiguredNetworks(); 22 | hookWifiScannedNetworks(); 23 | hookWifiInfoMethods(); 24 | } 25 | 26 | protected void hookUtilsGetDefaultWifiIpAddresses() { 27 | Class[] params = new Class[1]; 28 | params[0] = Context.class; 29 | hookAndSaveReturnValue("com.android.settings.Utils", 30 | "getDefaultIpAddresses", params); 31 | // must return Utils.getFormatedIpFromIp(String); 32 | } 33 | 34 | public void hookWifiInfoMethods() { 35 | Class[] params = new Class[0]; 36 | String wifiInfo = "android.net.wifi.WifiInfo"; 37 | hookAndSaveReturnValue(wifiInfo, "getBSSID", params); 38 | hookAndSaveReturnValue(wifiInfo, "getIpAddress", params); 39 | hookAndSaveReturnValue(wifiInfo, "getMacAddress", params); 40 | hookAndSaveReturnValue(wifiInfo, "getSSID", params); 41 | } 42 | 43 | protected static int fakeIP() { 44 | return getRealIPFrom("192.168.0.2"); 45 | } 46 | 47 | @Override 48 | protected Object convertFromProfile(String clazz, String method, String value) { 49 | if (method.equals("getFormatedIpFromIp") 50 | || method.equals("getWifiIpAddresses")) 51 | return Utils.getFormatedIpFromIp(getRealIPFrom("192.168.0.2")); 52 | else if (method.equals("getConfiguredNetworks")) 53 | return getDummyConfiguredNetworks(); 54 | else if (method.equals("getScanResults")) 55 | return getDummyScannedNetworks(); 56 | else 57 | return value; 58 | } 59 | 60 | private Object getDummyScannedNetworks() { 61 | // TODO Auto-generated method stub 62 | return null; 63 | } 64 | 65 | private Object getDummyConfiguredNetworks() { 66 | // TODO Auto-generated method stub 67 | return null; 68 | } 69 | 70 | private static int getRealIPFrom(String ipAddress) { 71 | String[] octets = ipAddress.split("\\."); 72 | return (Integer.parseInt(octets[3]) << 24) 73 | + (Integer.parseInt(octets[2]) << 16) 74 | + (Integer.parseInt(octets[1]) << 8) 75 | + Integer.parseInt(octets[0]); 76 | } 77 | 78 | protected void hookWifiConfiguredNetworks() { 79 | Class[] params = new Class[0]; 80 | hookAndSaveReturnValue("android.net.wifi.WifiManager", 81 | "getConfiguredNetworks", params); 82 | } 83 | 84 | protected void hookWifiScannedNetworks() { 85 | Class[] params = new Class[0]; 86 | hookAndSaveReturnValue("android.net.wifi.WifiManager", 87 | "getScanResults", params); 88 | } 89 | 90 | } 91 | --------------------------------------------------------------------------------