Zum Inhalt springen

PersistenzAusführung

LaunchAgents und LaunchDaemons: Persistenz unter macOS

launchd-Plists in LaunchAgents und LaunchDaemons legen fest, was macOS beim Booten, bei der Anmeldung oder nach Zeitplan startet: Persistenzort Nummer eins.

Speicherort
~/Library/LaunchAgents, /Library/LaunchAgents, /Library/LaunchDaemons
Belegt
Welcher Code automatisch startet, als welcher Benutzer, bei welchem Auslöser und seit wann
Zeitstempel
Keine internen Zeitstempel; APFS-Dateizeiten (Nanosekunden, UTC)
Zugriff
Benutzer-Agents: besitzender Benutzer; /Library: root; FDA für das Sicherungstool empfohlen
Aufbewahrung
Bis die Plist gelöscht wird; Overrides und BTM-Einträge können sie überdauern
Sicherung
Aftermath, mac_apt, UAC, Velociraptor

Was es ist

launchd ist unter macOS PID 1. Er startet System-Daemons beim Booten und Benutzer-Agents bei der Anmeldung anhand von Job-Definitionen, die als Property Lists gespeichert sind. Eine Job-Plist nennt ein Label, das auszuführende Programm und die Auslöser (beim Laden, dauerhaft am Leben halten, Intervall, Kalender, Änderungen an Dateipfaden). Legitime Software und die meiste macOS-Malware nutzen genau denselben Mechanismus. Deshalb sind diese Ordner die erste Anlaufstelle bei jeder Prüfung auf Persistenz.

Daemons laufen im Systemkontext (als root, sofern UserName nichts anderes angibt) ohne angemeldeten Benutzer. Agents laufen innerhalb der Sitzung eines Benutzers.

Wo es liegt

PfadTypGeschrieben vonmacOS / Schutz
~/Library/LaunchAgentsAgent pro BenutzerDer Benutzer, keine Admin-Rechte nötigAlle Versionen
/Library/LaunchAgentsAgent für jeden BenutzerAdministrator (root)Alle Versionen
/Library/LaunchDaemonsSystem-DaemonAdministrator (root)Alle Versionen
/System/Library/LaunchAgents, /System/Library/LaunchDaemonsApple-JobsAppleVersiegeltes Systemvolume ab 11 Big Sur
/Library/Apple/System/Library/LaunchAgents, .../LaunchDaemonsApple-Jobs auf dem Data-VolumeAppleDurch SIP geschützt
<App>.app/Contents/Library/LaunchAgents, .../LaunchDaemonsIn Apps gebündelte Jobs, registriert mit SMAppServiceEntwicklerAb 13 Ventura
/private/var/db/com.apple.xpc.launchd/disabled.plist, disabled.<UID>.plistEnable/Disable-Overrides von launchdlaunchctl enable/disableroot
/private/var/db/com.apple.xpc.launchd/loginitems.<UID>.plistAnmeldeobjekte des Service ManagementSMLoginItemSetEnabledroot
/Library/StartupItemsAlte StartobjekteAdministratorVeralteter Mechanismus

Prüfen Sie außerdem /var/root/Library/LaunchAgents und jedes Home-Verzeichnis unter /Users.

Was es belegt

  • Dass ein Programm so konfiguriert war, dass es beim Booten, bei der Anmeldung, in einem Intervall, nach Kalenderplan, bei Dateiänderungen oder beim Einhängen eines Volumes startet.
  • Das Konto, unter dem der Job läuft (ein Daemon ohne UserName bedeutet root).
  • Das Schreiben nach /Library/LaunchDaemons erforderte root, ein bösartiger Daemon impliziert also eine Rechteausweitung.
  • Mit dem Laufzeitzustand (launchctl print): ob der Job geladen ist, seine PID, die Anzahl der Läufe und der letzte Exit-Status.

Eine Plist allein belegt nicht, dass der Job je lief: Er kann durch ein Override deaktiviert sein, nicht laden oder auf ein fehlendes Binärprogramm zeigen. Untermauern Sie das mit Logs und Prozessbelegen.

Wichtige Felder

Aus launchd.plist(5):

SchlüsselBedeutung
LabelEindeutiger Job-Name (Pflicht)
Program / ProgramArgumentsAusführbare Datei und Argumentvektor
BundleProgramAusführbare Datei relativ zur App, nur in SMAppService-Plists
RunAtLoadStart beim Laden (Boot oder Anmeldung)
KeepAliveNeustart nach Beenden oder bedingtes Dictionary
StartInterval / StartCalendarIntervalPeriodischer oder geplanter Start
WatchPaths / QueueDirectories / StartOnMountAuslöser im Dateisystem
UserName / GroupNameAusführungsidentität
EnvironmentVariablesUmgebung (auf DYLD_INSERT_LIBRARIES achten)
StandardOutPath / StandardErrorPathAusgabedateien, oft nützliche Belege
LimitLoadToSessionTypeSitzungstypen für Agents (z. B. Aqua)
AssociatedBundleIdentifiersApp, die für diesen Job in den Einstellungen für Anmeldeobjekte angezeigt wird
DisabledStandardzustand; der Zustand von launchctl enable/disable wird extern gespeichert

Zeitstempel

Plists haben kein eigenes Erstellungsdatum. Nutzen Sie das Dateisystem: APFS speichert Erstellungs-, Änderungs-, Statusänderungs- und Zugriffszeiten mit Nanosekundengenauigkeit in UTC.

stat -f '%SB | %Sm | %N' -t '%Y-%m-%d %H:%M:%S' ~/Library/LaunchAgents/*.plist

Die Erstellungszeit ist meist der beste Anker für „installiert am“, kann aber mit touch oder durch Kopierwerkzeuge verändert werden. Prüfen Sie die Zeiten des referenzierten Binärprogramms, FSEvents für den Ordner und den Eintrag im Background Task Management.

Aufbewahrung

Ein Job bleibt bestehen, bis seine Plist entfernt wird. Das Entfernen löscht nicht alles: Overrides in disabled*.plist, Einträge im Background Task Management, Einträge im Unified Log, FSEvents, lokale APFS-Snapshots und Time-Machine-Backups können Spuren bewahren.

Sicherung

# Dead-box or live (root, Full Disk Access)
sudo ditto /Library/LaunchAgents ./case/la_system
sudo ditto /Library/LaunchDaemons ./case/ld_system
sudo ditto /private/var/db/com.apple.xpc.launchd ./case/launchd_db
for u in /Users/*; do [ -d "$u/Library/LaunchAgents" ] && \
  sudo ditto "$u/Library/LaunchAgents" "./case/la_$(basename "$u")"; done

# Live state (read-only)
sudo launchctl print system > ./case/launchctl_system.txt
launchctl print gui/501 > ./case/launchctl_gui501.txt
sudo launchctl print-disabled system > ./case/disabled_system.txt
  • UAC files/system/startup_items.yaml sichert die Standardordner für Agents und Daemons (pro Benutzer, /Library, /System/Library und /Library/Apple/System/Library, jedoch nicht /var/root oder in Apps gebündelte Jobs), /Library/StartupItems und loginitems.*.plist; live_response/system/launchctl.yaml führt launchctl list aus.
  • Aftermath sichert Launch Agents und Daemons als Teil seiner Persistenzobjekte.
  • Führen Sie niemals launchctl bootout, unload oder disable aus, bevor Sie dokumentiert haben.

Auswertung

  • plutil: plutil -p <file> gibt XML- oder Binär-Plists aus; plutil -lint markiert fehlerhafte.
  • Plugin AUTOSTART von mac_apt: python mac_apt.py -o out E01 mac.E01 AUTOSTART.
  • Plugin launchd_plist von Plaso: log2timeline.py --parsers 'plist/launchd_plist' --storage-file ld.plaso ./case.
  • KnockKnock (objective-see/KnockKnock) listet persistente Objekte auf einem Live-Mac mit Signaturstatus auf.

Schnelle Sichtung des Programms jedes Jobs:

for f in /Library/Launch*/*.plist ~/Library/LaunchAgents/*.plist; do
  printf '%s\t' "$f"; plutil -extract ProgramArguments json -o - "$f" 2>/dev/null \
    || plutil -extract Program raw -o - "$f"; echo
done

Tipps für die Untersuchung

  • Ein Label com.apple.* außerhalb von /System und /Library/Apple ist ein Warnsignal: Apple-Jobs liegen nicht in /Library/LaunchDaemons.
  • Beginnt ProgramArguments mit /bin/sh, /bin/bash, /usr/bin/python3 oder /usr/bin/osascript, ist der Interpreter von Apple signiert; das Skript-Argument ist die eigentliche Nutzlast.
  • Hashen und prüfen Sie jedes Ziel: codesign -dv --verbose=4, spctl --assess -vv, xattr -l für die Quarantäne.
  • Ziele in versteckten Ordnern, /tmp, /Users/Shared oder Namen, die nach Herstellern klingen, unter ~/Library/Application Support verdienen Vorrang.
  • Ein Job, den launchctl print als geladen zeigt, der aber keine Plist auf der Platte hat, bedeutet, dass die Datei nach dem Laden entfernt wurde.
  • Vergleichen Sie mit dem Standard-Build der Organisation: Updater, VPN, MDM und Backup-Agents sind normales Grundrauschen.
  • Prüfen Sie auch cron und periodic und lesen Sie den Leitfaden zur launchd-Persistenz.

Siehe auch