android - troyano - ¿Cómo puede una aplicación detectar que se va a desinstalar?
ventanas emergentes android virus (4)
Bueno. He estado investigando mucho sobre este problema desde hace 2 días y finalmente encontré una "manera salvaje" de resolverlo sin rootear el dispositivo :)
Primero, aquí están los aspectos más destacados para lograr la solución:
1. Cada vez que el usuario va a Configuración -> Administrar aplicaciones -> Selecciona una aplicación en particular , recibimos una transmisión android.intent.action.QUERY_PACKAGE_RESTART con el nombre del paquete de la aplicación como extras.
2. Después de eso, cuando hacemos clic en el botón Desinstalar (con el instalador del paquete), se abre una actividad llamada - com.android.packageinstaller.UninstallerActivity
El flujo de control será como:
En Configuración de la aplicación, el usuario hace clic en el botón Desinstalar ---> Obtenemos control para mostrar un diálogo / iniciar otra actividad / etc ---> Terminamos nuestra tarea previa a la desinstalación ---> El usuario vuelve a la pantalla de confirmación de desinstalación - -> El usuario confirma y desinstala la aplicación
Método utilizado:
Implementaremos un BroadcastReceiver en nuestra aplicación para escuchar la acción " android.intent.action.QUERY_PACKAGE_RESTART " y unir nuestro nombre de paquete dentro del método onReceive (). Si la transmisión se recibió para la selección de nuestro paquete de aplicaciones deseado, iniciaremos un hilo de fondo que seguirá monitoreando las actividades de ejecución en primer plano usando el ActivityManager.
Una vez que encontremos que la actividad de primer plano sea " com.android.packageinstaller.UninstallerActivity ", se confirmará que el usuario desea desinstalar nuestra aplicación. En este punto realizaremos las tareas deseadas (ya sea mostrar un diálogo o iniciar otra actividad que se superponga a la ventana de desinstalación, etc.) que se realizarán antes de la desinstalación. Después de realizar nuestra tarea, le permitiremos al usuario continuar confirmando el proceso de desinstalación.
Implementación / Código fuente:
En manifest.xml
agregar permiso:
<uses-permission android:name="android.permission.GET_TASKS"/>
y receptor de difusión:
<receiver android:name=".UninstallIntentReceiver">
<intent-filter android:priority="0">
<action android:name="android.intent.action.QUERY_PACKAGE_RESTART" />
<data android:scheme="package" />
</intent-filter>
</receiver>
UninstallIntentReceiver.java (clase de receptor de difusión)
public class UninstallIntentReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
// fetching package names from extras
String[] packageNames = intent.getStringArrayExtra("android.intent.extra.PACKAGES");
if(packageNames!=null){
for(String packageName: packageNames){
if(packageName!=null && packageName.equals("YOUR_APPLICATION_PACKAGE_NAME")){
// User has selected our application under the Manage Apps settings
// now initiating background thread to watch for activity
new ListenActivities(context).start();
}
}
}
}
}
Clase ListenActivities : para supervisar las actividades en primer plano
class ListenActivities extends Thread{
boolean exit = false;
ActivityManager am = null;
Context context = null;
public ListenActivities(Context con){
context = con;
am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
}
public void run(){
Looper.prepare();
while(!exit){
// get the info from the currently running task
List< ActivityManager.RunningTaskInfo > taskInfo = am.getRunningTasks(MAX_PRIORITY);
String activityName = taskInfo.get(0).topActivity.getClassName();
Log.d("topActivity", "CURRENT Activity ::"
+ activityName);
if (activityName.equals("com.android.packageinstaller.UninstallerActivity")) {
// User has clicked on the Uninstall button under the Manage Apps settings
//do whatever pre-uninstallation task you want to perform here
// show dialogue or start another activity or database operations etc..etc..
// context.startActivity(new Intent(context, MyPreUninstallationMsgActivity.class).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
exit = true;
Toast.makeText(context, "Done with preuninstallation tasks... Exiting Now", Toast.LENGTH_SHORT).show();
} else if(activityName.equals("com.android.settings.ManageApplications")) {
// back button was pressed and the user has been taken back to Manage Applications window
// we should close the activity monitoring now
exit=true;
}
}
Looper.loop();
}
}
Limitaciones conocidas:
Cuando el usuario haga clic en el botón Desinstalar en la configuración de Administrar aplicaciones, realizaremos nuestras tareas previas a la desinstalación y luego enviaremos al usuario a la ventana de Confirmación donde el usuario puede confirmar la desinstalación o puede cancelar la operación.
El enfoque descrito anteriormente no cubre ahora el caso si el usuario hace clic en el botón Cancelar después de haber realizado nuestra tarea. Pero esto podría abordarse fácilmente con algunas enmiendas.
Por ejemplo: podemos implementar una lógica para revertir los cambios que hicimos si la transmisión " android.intent.action.PACKAGE_REMOVED " no se recibiera al final.
Espero que este enfoque sea útil para ti :) ¡Como esta es la única forma en mi opinión, podemos resolver tu problema sin rootear el dispositivo!
[Actualización 1] : Enfoque sugerido para verificar si la tarea de desinstalación fue cancelada :
Es curioso que tuve una idea completamente diferente y muy compleja antes (involucrando transmisiones, ActivityManager, etc. ...), pero mientras la escribía aquí me vino a la cabeza otra idea que es comparativamente muy simple :)
Cuando el usuario hace clic en el botón Desinstalar debajo de la configuración de Administrar aplicaciones y después de haber realizado las tareas previas a la desinstalación, simplemente configura SharedPreference en su aplicación que ya realizó las tareas previas a la desinstalación y está listo para la desinstalación. Después de esto, no necesita preocuparse por nada.
Si el usuario continúa desinstalando -> está bien y bien, ya que ya ha realizado las tareas requeridas.
Mientras que si el usuario finalmente hace clic en el botón Cancelar y se va -> no te molestes. Hasta que el usuario vaya y vuelva a ejecutar su aplicación. Ahora dentro de "onStart ()" / "onResume ()" de la actividad principal de su aplicación, puede verificar el valor de SharedPreference y si se configuró para la desinstalación, eso significará que el usuario finalmente no procedió con la desinstalación. ¡Y ahora podría revertir los cambios realizados anteriormente (invirtiendo las tareas previas a la desinstalación realizadas) para garantizar que su aplicación se ejecute perfectamente!
Esta pregunta ya tiene una respuesta aquí:
Todos sabemos que la aplicación antivirus habitual (en la práctica, cualquier) antes de la desinstalación solía generar un diálogo simple como: "Vas a desinstalar la aplicación, ¿estás seguro?" - "si no".
Sí, sé que puedo interceptar el intento de eliminación del paquete usando intent-filter como:
<activity
android:name=".UninstallIntentActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.DELETE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="package" />
</intent-filter>
</activity>
Pero el problema está en el hecho simple de que esto intercepta cualquier solicitud de eliminación y además esto disparará el diálogo del selector entre mi aplicación y el instalador de valores. Entonces, si el usuario selecciona el instalador de stock, no podré hacer nada.
Mi objetivo no es evitar que el usuario desinstale mi aplicación, sino solo deshacer los cambios realizados por mi aplicación.
Aprendiendo de esas aplicaciones de antivirus veo que este tipo de operación es posible, así que por favor ayúdenme y explique cómo es posible.
Actualizar
Dado que hay algunos tipos que no creen que sea real, me referiría a Avast Mobile Security :
Anti-Theft se protege de la desinstalación al disfrazar sus componentes con diversas técnicas de autopreservación.
Otro ejemplo: Kaspersky Internet Security para Android: este es un procedimiento especial para desinstalarlo , que requiere la introducción de un código secreto.
De todos modos, significa que hay forma de interceptar el procedimiento de desinstalación para evitar la desinstalación o realizar algún trabajo de finalización.
Otra opción para detectar la desinstalación de aplicaciones es usar código nativo.
Necesita supervisar su directorio utilizando inotify
framework en el proceso bifurcado.
Cuando se elimina Puede ejecutar algún comando del sistema, por ej. am
comando que comienza Intent
PoC de dicha solución: https://github.com/pelotasplus/ActionAfterUninstall/blob/master/app/src/main/jni/hello-jni.c
Para que su aplicación persista, deberá tener un dispositivo rooteado y poder instalarlo en la partición del sistema. Una vez allí, puede desinstalar las actualizaciones, ya que se guardan junto con las aplicaciones que no son del sistema, pero no es tan sencillo como desinstalarlas del sistema.
Sé que algunos de ellos también guardarán un poco de datos en la partición del sistema en caso de que los dispositivos se restablezcan a los valores de fábrica, pero también hay formas de que el administrador de paquetes deje sus datos guardados en caso de que solo se desinstalen. .
Otra opción sería registrarlo como administrador del dispositivo. Una vez que lo hagas, no podrán desinstalarlo a menos que eliminen manualmente su estado de administrador.
<item name="android.permission.ACCESS_SUPERUSER" />
Aquí parece que están usando root y otros métodos. A menos que hagan un servicio complicado y loco, que parece que pueden tener, no hay una forma legítima de hacerlo de otra manera.
Aprovechar Root es una práctica casi estándar para AV / aplicaciones de seguridad como esta, sin esto no tienen ninguna autoridad real sobre ninguna otra aplicación, por lo que son muy limitadas. Creo que el permiso SuperUser no se muestra a menos que lo tengas instalado tampoco, por lo que muchas personas aún no saben que es una opción.
<perms>
<item name="android.permission.READ_EXTERNAL_STORAGE" />
<item name="android.permission.GET_TASKS" />
<item name="android.permission.PROCESS_OUTGOING_CALLS" />
<item name="android.permission.WRITE_EXTERNAL_STORAGE" />
<item name="android.permission.WRITE_CALL_LOG" />
<item name="com.avast.android.generic.CENTRAL_SERVICE_PERMISSION" />
<item name="android.permission.WRITE_SMS" />
<item name="android.permission.ACCESS_WIFI_STATE" />
<item name="android.permission.RECEIVE_SMS" />
<item name="android.permission.GET_ACCOUNTS" />
<item name="android.permission.READ_CONTACTS" />
<item name="android.permission.CALL_PHONE" />
<item name="android.permission.WRITE_CONTACTS" />
<item name="android.permission.READ_PHONE_STATE" />
<item name="android.permission.READ_SMS" />
<item name="android.permission.RECEIVE_BOOT_COMPLETED" />
<item name="android.permission.ACCESS_SUPERUSER" />
<item name="com.avast.android.mobilesecurity.permission.C2D_MESSAGE" />
<item name="android.permission.GET_PACKAGE_SIZE" />
<item name="android.permission.WAKE_LOCK" />
<item name="android.permission.ACCESS_NETWORK_STATE" />
<item name="android.permission.USE_CREDENTIALS" />
<item name="android.permission.SEND_SMS" />
<item name="android.permission.RECEIVE_MMS" />
<item name="com.google.android.c2dm.permission.RECEIVE" />
<item name="android.permission.KILL_BACKGROUND_PROCESSES" />
<item name="com.android.vending.BILLING" />
<item name="android.permission.WRITE_SETTINGS" />
<item name="android.permission.INTERNET" />
<item name="android.permission.VIBRATE" />
<item name="android.permission.READ_CALL_LOG" />
<item name="com.avast.android.generic.COMM_PERMISSION" />
<item name="com.dolphin.browser.permission.ACCESS_PROVIDER" />
<item name="com.android.browser.permission.READ_HISTORY_BOOKMARKS" />
</perms>
Simplemente no es posible en Android
No hay forma de que su aplicación sepa que se está desinstalando (sin modificar el kernel). Todos los archivos creados en data / data / your.app.package se eliminan automáticamente durante la instalación.
Otro enfoque podría ser tener otra aplicación que verifique si esta aplicación está instalada o no. Si no, puede hacer el trabajo de limpieza.
ACTUALIZAR
El intento ACTION_PACKAGE_REMOVED se enviará a todos los receptores, excepto el tuyo. Esto se confirma HERE .
ACTUALIZACIÓN 2
Solo otro pensamiento.
mientras buscaba esto descubrí que esto se puede hacer monitoreando Logcat para su aplicación. here hay un monitor logcat de muestra
Lo bueno es que para monitorear Logcat para la misma aplicación no necesitamos tener un dispositivo rooteado
y mientras leemos cada entrada en logcat podemos buscar la siguiente cadena
Received broadcast Intent { act=android.intent.action.PACKAGE_REMOVED dat=package:com.package.name flg=0x8000010 (has extras) }
cuando se recibe este evento, sabemos que nuestra aplicación ahora se va a instalar
No intenté sin embargo
Nuevamente, el monitoreo de logcat no está permitido desde Android Jellybean