Wie führe ich eine ausführbare Datei beim Booten aus und halte sie am Laufen?

Ich habe einen ausführbaren Build aus einem ndk-buildProgramm. Ich möchte es auf einem gerooteten Android-Gerät ausführen. Wie groß ist die Wahrscheinlichkeit, dass Android meine ausführbare Datei tötet?

Mit adb shellkann ich meine ausführbare Datei mit folgenden Befehlen ausführen:

adb push executable /sdcard
adb shell
device:/ $ su
device:/ # cd /system
device:/system # mount -o rw,remount /system
device:/system # mv /sdcard/executable .
device:/system # ./executable

Meine Anforderung ist, diese ausführbare Datei beim Gerätestart auszuführen.

Folgendes habe ich probiert:

  1. Schreiben Sie ./executableein init.rc.
    • Beim Neustart init.rcauf den ursprünglichen Inhalt zurückgesetzt. Ich habe herausgefunden, dass Magisk dies getan hat.
  2. Schreiben Sie Befehle in /system/etc/init/bootstat.rc
    • ./executable
    • service custom /system/executable
    • on boot ./system/dhandler/diag_revealer

Keines der oben genannten Dinge funktioniert.

Kommentare sind nicht für längere Diskussionen gedacht; Diese Konversation wurde in den Chat verschoben .

Antworten (1)

Wie groß ist die Wahrscheinlichkeit, dass Android meine ausführbare Datei tötet?

Privilegierte native Prozesse werden normalerweise nicht von Android beendet, es sei denn, sie können einen darin aufgetretenen Fehler nicht verarbeiten, z dh läuft unter zygote. Um Ressourcen für native Prozesse zu verwalten, verwendet Android cgroups.

Prozesse werden beendet, wenn sie SIGNALE vom Kernel oder anderen Userspace-Programmen erhalten (z. B. mit killdem Befehl) ( 1 , 2 ) . Der Kernel ist das eigentliche Betriebssystem, das für uns nicht sichtbar ist, aber alles verarbeitet, was wir mit dem Gerät tun. Ein Entwickler kann seinen Code so programmieren, wie er auf ein bestimmtes empfangenes Signal reagiert oder es komplett ignoriert ( 3 ) . Außer SIGKILL . Was nicht vom Programm gehandhabt werden kann, keine Warnung vom Kernel, keine Gnadenfrist zum sicheren Beenden, nur sofortige Beendigung. Aber der Kernel wird Ihre Anwesenheit nicht stören, es sei denn, ihm gehen die Hardware-Ressourcen aus oder Sie fangen an, sich schlecht zu benehmen. Deshalb ist Programmieren wichtig.

Programme können sich gegenseitig Signale senden (einschließlich KILL), die vom Kernel weitergeleitet werden, geregelt durch UID ( 4 ) . Allerdings initist der allererste Prozess im Userspace, der vom Kernel gestartet wird, der liebe, der Kernel leitet niemals gefährliche Signale an weiter init. Und wenn dies aus irgendeinem Grund passiert, gerät der Kernel in Panik und startet neu ( 5 ) .

Zusammenfassend lässt sich sagen, dass es möglich ist, das Töten (AMAP) programmgesteuert zu vermeiden oder einige Skripttricks zu verwenden, wie @alecxs erwähnt hat. Wenn Sie jedoch sicherstellen möchten, dass Ihr Prozess neu gestartet wird, wenn er beendet wird, definieren Sie einen Android- initDienst.

Beim Neustart init.rcauf den ursprünglichen Inhalt zurückgesetzt. Ich habe herausgefunden, dass Magisk dies getan hat.

Nein, Magisk hat das nicht getan. Android rootfsist ein temporäres Dateisystem (kein persistentes wie on /systemoder /data), das bei jedem Neustart gelöscht wird. Der Inhalt des Stammverzeichnisses ( /) wird aus einer anderen Partition mit dem Namen extrahiert, bootdie kernelund enthält ramdisk(obwohl sich die Dinge mit system-as-root geändert haben ). Sie können also nicht init.rcdauerhaft ändern, es sei denn, Sie extrahieren, modifizieren, neu packen und neu flashen boot.img.

Um jedoch einen neuen Init-Dienst zu definieren, init.rcist keine Änderung erforderlich. Android parst alle .rcDateien aus /etc/initVerzeichnissen unter /systemund /vendor ( 6 ) . Sie können also Ihre eigene .rcDatei erstellen.


HINWEIS: Um echte Root-Rechte zu erhalten und mit SELinux umzugehen, hängen alle unten angegebenen Optionen von Magisk ab. Siehe diese Antwort für Details.

INIT.D-SKRIPT

init.dSie können die traditionelle -ähnliche Funktion von Magisk verwenden, um einen Prozess beim Booten zu starten. Skript erstellen /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..."

* ist das PseudosignalEXIT der Shell .
* Android /system/bin/pkill(von toybox) ist fehlerhaft, verwenden Sie besser busyboxApplet.

Platzieren Sie die ausführbare Datei unter /system/binund legen Sie die Berechtigungen fest:

~# chown 0.0 /system/bin/executable /data/adb/service.d/custom.sh
~# chmod 0755 /system/bin/executable /data/adb/service.d/custom.sh

Sie können auch ein Skript unter platzieren, /data/adb/post-fs-data.d/aber das wird etwas früher ausgeführt. Stellen Sie sicher, dass Dateisystempfade (und ggf. andere erforderliche Ressourcen) zu diesem Zeitpunkt verfügbar sind.

PROGRAMM VON INIT AUSFÜHREN

Eine andere Möglichkeit besteht darin, die Binärdatei direkt von init auszuführen. custom.rcDatei erstellen :

#/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

Berechtigungen festlegen:

~# chown 0.0 /etc/init/custom.rc
~# chmod 0644 /etc/init/custom.rc
~# chcon u:object_r:system_file:s0 /etc/init/custom.rc

Und das ist alles! Starten Sie das Gerät neu, damit die Änderungen wirksam werden.

Es handelt sich jedoch um eine einmalige Ausführung, die nicht neu gestartet wird. Außerdem gibt es einige Shell-Scripting-Funktionen, die in .rcDateien nicht verfügbar sind. Beispielsweise können Sie stdout/stderr nicht in eine Datei umleiten, dies muss vom ausführbaren Programm selbst gehandhabt werden. Wir können also versuchen, beides zu nutzen; Shell-Skript und .rcDatei:

INIT-DIENST

Anstatt die Binärdatei direkt aus .rcder Datei auszuführen, führen Sie ein Shell-Skript aus. Skript erstellen /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

Dienst erstellen init:

#/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

Setzen Sie die Berechtigungen auf executableund custom.shwie custom.rcoben angegeben und starten Sie neu.

Andere Parameter ( 7 ) wie user, group, capabilitiessind erforderlich, wenn Sie den Dienst als nicht privilegierter Benutzer ausführen möchten. Das Gewähren der am wenigsten erforderlichen Berechtigungen ist aus Sicherheitssicht der empfohlene Ansatz. Weitere Informationen zu Funktionen und SELinux finden Sie in dieser Antwort .

initwird den Dienst alle 5 Sekunden (standardmäßig) neu starten, wenn er beendet wird. Sie können den Dienst mit beenden setprop ctl.stop custom. Ersetzen Sie stopdurch, startum neu zu beginnen.
So sehen Sie, was mit dem Service passiert: dmesg | grep init: | tail.

VERWANDTE :

Ein Skript in /data/adb/service.dwäre großartig, aber aus irgendeinem Grund scheinen diese Skripte nicht mit Root-Rechten zu laufen: using mount ...gibt mir "mount: Permission denied" und using su -c "mount ..."gibt mir "su: Permission denied". Fehlt mir etwas?