¿Cuánta es la posibilidad de que Android mate a mi ejecutable?
Los procesos nativos privilegiados no suelen ser eliminados por Android, excepto si no pueden manejar un error ocurrido en su interior, como algún recurso del sistema no disponible o permiso denegado debido a SELinux, etc. Para liberar memoria, Android sólo mata los procesos dentro de su marco de trabajo, es decir, ejecutándose bajo zygote
. Para administrar los recursos de los procesos nativos, Android utiliza cgroups
.
Los procesos se matan cuando reciben SEÑALES del kernel o de otros programas del espacio de usuario (por ejemplo, con kill
comando) ( 1 , 2 ) . El núcleo es el sistema operativo real, no visible para nosotros pero que maneja todo lo que hacemos con el dispositivo. Un desarrollador puede programar su código para reaccionar a una señal específica si se recibe, o ignorarla completamente. ( 3 ) . Excepto SIGKILL . Que no puede ser manejado por el programa, sin advertencia del núcleo, sin período de gracia para salir con seguridad, sólo ser terminado inmediatamente. Pero al kernel no le importará tu presencia a menos que le falten recursos de hardware o empieces a comportarte mal. Por eso es que la programación es importante.
Los programas pueden enviarse señales (incluyendo KILL), que son enviadas por el kernel, gobernado por UID ( 4 ) . Sin embargo, init
el primer proceso en el espacio de usuario iniciado por el núcleo es el querido, el núcleo nunca avanza peligroso señales para init
. Y si esto sucede por alguna razón, el núcleo entra en pánico y se reinicia ( 5 ) .
Resumiendo las líneas anteriores, es posible evitar ser asesinado (AMAP) de forma programada o usando algunos trucos de guión como @ alecxs ha mencionado. Pero si quiere asegurarse de que su proceso se reinicie si muere, defina un Android init
servicio.
Al reiniciar init.rc
y volver a su contenido original. Me di cuenta de que el Magisk hizo esto.
No, Magisk no hizo esto. El Android rootfs
es un sistema de archivos temporal (no uno persistente como en /system
o /data
) que se borra en cada reinicio. El contenido del directorio root ( /
) se extraen de otra partición llamada boot
que contiene kernel
y ramdisk
(aunque las cosas han cambiado con system-as-Root ). Así que no puedes cambiar init.rc
permanentemente a menos que extraigas, modifiques, vuelvas a empaquetar y vuelvas a poner en marcha boot.img
.
Pero para definir un nuevo servicio de inicio, modificando init.rc
no es necesario. El Android analiza todo .rc
archivos de /etc/init
Los directorios ubicados bajo /system
y /vendor
( 6 ) . Así que puedes crear tu propio .rc
archivo.
NOTA: Para obtener privilegios reales de root y para tratar con SELinux, todas las opciones que se dan a continuación dependen de Magisk. Véase esta respuesta para los detalles.
INIT.D script
Puedes usar el tradicional init.d
-como en Magisk para iniciar un proceso en el arranque. Crear script /data/adb/service.d/custom.sh
:
#!/system/bin/sh
# write log file if executable throws something at stdout/sterr
exec >>/data/media/0/executable.log 2>&1
# run script in background to avoid blocking boot chain
[ -n "$BG" ] || { BG=Y "$0" & exit; }
# try to ignore signals as much as possible
for i in $(seq 64); do trap '' "$i"; done
# execute script whenever exits e.g. when executable gets killed
trap "sleep 5; exec $0" EXIT
# avoid multiple instances e.g. if script killed but executable is running
pkill -9 -x /system/bin/executable
# execute the binary, should run in foreground, otherwise get in loop
echo "$(date): Starting program..."
/system/bin/executable
# program is killed, won't reach here if script is killed
echo "$(date): Re-executing script..."
* EXIT
es el de Shell pseudo-señal .
* Android's /system/bin/pkill
(de toybox
) es buggy, mejor usarlo busybox
applet.
Ponga el ejecutable bajo /system/bin
y establecer permisos:
~# chown 0.0 /system/bin/executable /data/adb/service.d/custom.sh
~# chmod 0755 /system/bin/executable /data/adb/service.d/custom.sh
También puedes colocar script bajo /data/adb/post-fs-data.d/
pero eso fue ejecutado un poco antes. Asegúrese de que las rutas del sistema de archivos (y otros recursos necesarios si los hay) estén disponibles en esa etapa.
EJECUTAR EL PROGRAMA DESDE EL INIT
Otra forma es ejecutar directamente el binario desde el inicio. Crear custom.rc
archivo:
#/etc/init/custom.rc
# execute the binary when boot is completed
on property:sys.boot_completed=1
exec_background u:r:magisk:s0 -- /system/bin/executable
Establecer los permisos:
~# chown 0.0 /etc/init/custom.rc
~# chmod 0644 /etc/init/custom.rc
~# chcon u:object_r:system_file:s0 /etc/init/custom.rc
¡Y eso es todo! Reinicie el dispositivo para que los cambios surtan efecto.
Sin embargo, es una ejecución de una sola vez, no se reiniciará. También hay algunas características de shell scripting que no están disponibles en .rc
archivos. Por ejemplo, no puedes redirigir stdout/stderr a un archivo, esto tiene que ser manejado por el propio programa ejecutable. Así que podemos intentar hacer uso de ambos; shell script y .rc
archivo:
SERVICIO DE INICIO
En lugar de ejecutar directamente el binario de .rc
ejecutar un archivo de shell script. Crea script /system/bin/custom.sh
:
#!/system/bin/sh
# write log file if executable throws something at stdout/sterr
exec >>/data/media/0/executable.log 2>&1
# execute the binary, should run in foreground, otherwise get in loop
echo "$(date): Starting program..."
exec /system/bin/executable
Crear init
servicio:
#/etc/init/custom.rc
# define service, use executable here if script not needed
service custom /system/bin/custom.sh
# don't start unless explicitly asked to
disabled
# only execute once, don't restart if exited
# don't add if you want to restart service when killed
#oneshot
# run with unrestricted SELinux context to avoid avc denials
# it's required if SELinux is enforcing and service needs access
# to some system resources not allowed by default sepolicy
seclabel u:r:magisk:s0
# start the service when boot is completed
on property:sys.boot_completed=1
start custom
Establezca los permisos de todos los archivos como se indica arriba y reinicie.
Otros parámetros ( 7 ) como user
, group
, capabilities
son necesarias si se quiere ejecutar el servicio como usuario no privilegiado. Concediendo los privilegios menos requeridos es el enfoque recomendado desde la perspectiva de la seguridad. Véase esta respuesta para más detalles sobre las capacidades y SELinux.
init
seguirá reiniciando el servicio cada 5 segundos (por defecto) si se mata. Puede detener el servicio con setprop ctl.stop custom
. Reemplaza stop
con start
para empezar de nuevo.
Para ver qué pasa con el servicio: dmesg | grep init: | tail
.
1 votos
Los comentarios no son para ampliar la discusión; esta conversación ha sido trasladado al chat .