Obtener permisos de superusuario – Capítulo 10 – Curso Android

0

En el curso Android que acabamos esta semana hemos explicado las estructuras básicas que os permitirán implementar vuestras aplicaciones, pasando por las actividades y los threads, y sin olvidar los servicios, los permisos y el paso de mensajes entre aplicaciones.

En esta sesión, y pese a que provablemente no os será de utilidad más que en unos pocos casos, queremos explicaros cómo conseguir privilegios de administrador en vuestras aplicaciones, lo que os permitirá desarrollar aplicaciones que se ejecuten sin las restricciones impuestas por el sistema.

Como hemos indicado en muchas ocasiones en nuestros posts de índole general, Android es un sistema estructurado en capas, cada una de las cuales interacciona con las capas superior e inferior e incorpora un nivel de abstracción diferente.

En concreto, las aplicaciones se ejecutan sobre Dalvik, la máquina virtual que incorpora Android y que se encarga de la ejecución de las aplicaciones, incluyendo tanto las que pertenecen al sistema como al usuario, y delegando en el sistema la gestión de procesos y memoria.

Dalvik ejecuta las aplicaciones en el contexto del usuario al que pertenecen, que se crea en el momento en que éstas se instalan y esto no puede cambiarse, lo que imposibilita la inclusión de código privilegiado directamente en las aplicaciones y obliga a la creación de un proceso separado, como veremos más adelante.

Captura de pantalla de superuser

Cómo funciona el root

La adquisición del root en terminales Android es realmente ingeniosa, y se divide en dos partes claramente diferenciadas.

  • Por un lado un programa que pertenece al usuario root y que tiene activo el bit SUID, lo cual permite que su ejecución se realice usando el código de usuario al que pertenece el programa (root en este caso) y no el código de usuario que realiza la llamada (el asignado a nuestra aplicación), y que lo único que hace es ejecutar el programa que recibe como parámetro, habitualmente un shell, una vez comprobado que el usuario ha decidido permitirlo,
  • Por otro lado una aplicación, con interfaz gráfica, y que no dispone de ningún privilegio especial, que se encarga de mostrar un diálogo al usuario cada vez que una aplicación desea obtener privilegios de superusuario y que simplifica la gestión de dichos permisos, la visualización de logs, etc.

Aplicaciones como SuperUser y SuperSU implementan esta interfaz gráfica, todo y que, bajo determinadas situaciones, son capaces de actualizar y/o descargar también el archivo binario asociado.

Obtención del root en una aplicación

Como hemos indicado anteriormente, la obtención de los permisos de superusuario no puede hacerse en el contexto del proceso que se está ejecutando, sino que deberemos ejecutar un proceso externo, que será el que ejecute el código privilegiado y del que deberemos capturar la salida para comprobar si la ejecución ha sido correcta o no.

Pese a que podemos ejecutar un comando cada vez, lo más habitual es que el comando que se ejecute sea una shell, lo que permitirá la ejecución de varios comandos de forma secuencial, pudiendo capturar la salida de cada uno de ellos de forma separada.

Esta forma de actuar permite, además, que la solicitud de los permisos de superusuario (por medio de la aplicación SuperUser o SuperSU) se realice una única vez, cuando se inicia el shell, y no cada vez que se ejecuta un comando.

iProcess = Runtime.getRuntime().exec(“su -c sh”);

Capturando la salida del proceso privilegiado

Todo proceso Unix estándar dispone de dos canales por los que expulsa el resultado de las operaciones que ejecuta: el canal de salida, que es aquel en el que se imprimen el resultado de las operaciones print, write y, en general, aquellas funciones y procedimientos que imprimen resultados y, el canal de errores, en el que se escriben los códigos y mensajes de error y advertencias.

Adicionalmente, es necesario abrir un canal que permita enviar los comandos al proceso privilegiado que acabamos de crear, y que en Unix se conoce como canal de entrada del proceso.

iDataOutputStream = new DataOutputStream(iProcess.getOutputStream());
iDataInputStream = new DataInputStream(iProcess.getInputStream());
iDataErrorStream = new DataInputStream(iProcess.getErrorStream());

Enviando comandos al proceso privilegiado

Una vez abierto el canal de entrada estándar del proceso privilegiado, la ejecución de comandos se realiza cada vez que enviamos una línea de texto por dicho canal.

public boolean execute(String command)
{
  iDataOutputStream.writeBytes(command + “\n”);
  iDataOutputStream.flush();
}

Recibiendo resultados del proceso privilegiado

Del mismo modo, la recepción de resultados se realiza leyendo de los canales de salida y errores, tal como se muestra más abajo.

public List getStandardOutput()
{
  List results = new ArrayList();
  String line;
  while (true)
  {
    line = iDataInputStream.readline();
    if (line == null) break;
    results.add(line);
  }
  return results;
} 

public List getStandardErrorsOutput()
{
  List results = new ArrayList();
  String line;
  while (true)
  {
    line = iDataErrorStream.readline();
    if (line == null) break;
    results.add(line);
  }
  return results;
}

Comprobación de los permisos

El método más sencillo para comprobar si la obtención de los permisos de superusuario ha sido exitosa es la ejecución del comando id, que nos proporcionará información sobre el usuario que está ejecutando la aplicación y que debería ser 0 en caso afirmativo.

execute(“id”);
List output = getStandardOutput();
if ((output == null) || (output.isEmpty())) 
  throw new Exception("Can't get root access or denied by user");
if (! output.toString().contains("uid=0"))  
  throw new Exception("Root access rejected by user or device isn't rooted");

Acabar la sesión

Una vez que se han ejecutado todos los comandos necesarios, será conveniente finalizar la sesión de shell, mediante la ejecución del comando exit, que provocará la finalización del proceso asociado y el cierre de los canales de comunicaciones asociados al mismo.

Capturas de pantalla

Con esto damos por finalizado nuestro curso Android, no sin antes agradeceros vuestra atención y animaros a descargaros la última versión del mismo, que incluye el código completo necesario para conseguir permisos de superusuario en vuestras aplicaciones.

Como siempre, os invitamos a visitar el Hilo oficial del Curso de Android de Foromóviles, donde podéis hacernos llegar vuestras dudas y comentarios.

Sin comentarios

Dejar respuesta