Forside › Analyse og fortolkning · Gennemgået oktober 2026 · Af John Nielsen
Ikke alle apps gemmer deres data i SQLite. Apple-platformene bruger property lists (plist) til indstillinger og mange former for tilstand. Chromium-browsere og de mange desktopapps, der er bygget med Electron, gemmer lokal lagring og IndexedDB i LevelDB. Formaterne er velbeskrevne, men de kræver særlige parsere, og de har hver deres regler for, hvornår slettede data forsvinder. Kender man dem ikke, overser man let spor, eller man fortolker en gammel værdi som en aktuel.
SQLite er beskrevet for sig i SQLite i forensic. Her gennemgås de øvrige formater, der oftest optræder i app-data.
Property lists (plist)
En plist er en struktureret fil med ordbøger, lister, tekst, tal, datoer og binære data. Den findes i tre former:
- XML · Læsbar tekst, der starter med en XML-erklæring og et plist-element
- Binær · Starter med teksten
bplist00og er kompakt og ikke direkte læsbar - NSKeyedArchiver · En binær plist, der indeholder en serialiseret objektgraf med en liste over objekter og henvisninger mellem dem
XML og binær plist kan konverteres til hinanden uden tab, og alle almindelige plist-værktøjer kan læse begge. NSKeyedArchiver-formatet er sværere. Data ligger i en flad liste, og værdierne henviser til hinanden med indeks. En naiv visning giver en lang liste af tilsyneladende usammenhængende værdier. Et værktøj, der kan genskabe objektgrafen, er nødvendigt for at se, hvilken værdi der hører til hvilket felt.
Datoer i plist gemmes som sekunder siden 1. januar 2001 UTC, Apples epoke. Felter med tal, der ligner tidsstempler, kan også være i Unix-tid eller andre formater, afhængigt af appen. Se Tidsstempelformater.
Plist-filer bruges til indstillinger, seneste filer, netværk, tilsluttede enheder og meget andet på macOS og iOS. Mange af de klassiske artefakter er beskrevet i macOS-artefakter. På iPhone findes også plist-filer i apps’ egne mapper og i backup.
Slettede data i plist
En plist skrives som regel helt om, når den ændres. Der er derfor ingen intern historik i filen. Tidligere versioner kan findes:
- i backup og snapshots af filsystemet,
- som slettede filer i ikke-allokeret plads (unallocated),
- i kopier, som appen selv har gemt, fx midlertidige filer.
En plist viser altså normalt kun den aktuelle tilstand, og et felts værdi siger ikke, hvornår feltet fik den.
LevelDB
LevelDB er en nøgle-værdi-database, som Google har udviklet, og som Chromium bruger til blandt andet Local Storage, Session Storage og IndexedDB. Electron-apps arver det, så samme struktur findes i desktopversioner af mange samarbejdsværktøjer og beskedapps, se Electron-apps og lokale data.
En LevelDB-database er en mappe med flere filer:
CURRENTpeger på den aktuelleMANIFEST-fil.- MANIFEST beskriver, hvilke tabelfiler der indgår, og på hvilket niveau.
.loger en skrivelog, hvor nye skrivninger og sletninger først lægges..ldbeller.sster sorterede tabelfiler, hvor data ligger komprimeret i blokke.
Hver post har en nøgle, en værdi, et sekvensnummer og en type, der angiver, om posten er en skrivning eller en sletning. Når en nøgle slettes, skrives der en sletningsmarkør. Den gamle værdi forsvinder ikke med det samme. Den bliver liggende i loggen eller i ældre tabelfiler, indtil databasen komprimerer filerne og fjerner overflødige versioner.
Det giver to muligheder for en undersøgelse:
- Flere versioner af samme nøgle kan findes med hver sit sekvensnummer, så ændringer af en værdi kan følges.
- Slettede værdier kan genfindes, så længe komprimeringen ikke har fjernet dem.
Sekvensnumrene viser rækkefølge, ikke tid. Tidspunkter må komme fra værdierne selv eller fra filsystemets tidsstempler på de enkelte filer.
IndexedDB og værdiernes indhold
IndexedDB i Chromium bygger på LevelDB, men med en særlig kodning af nøgler, der rummer database-id, objektlager og indeks. Værdierne er ofte serialiserede JavaScript-objekter. Det kræver et værktøj, der forstår både LevelDB og Chromiums kodning, at få læsbare data ud. Firefox bruger i stedet SQLite til IndexedDB.
I Local Storage er værdierne typisk tekst, ofte JSON, som appen har gemt. Indholdet afhænger helt af appen: Det kan være brugerindstillinger, cache af beskeder, kladder eller id’er for den indloggede bruger. Betydningen af hvert felt må fastlægges ved at sammenligne med appens adfærd, helst på et testsystem.
Andre formater
- Core Data på Apple-platformene ligger normalt i SQLite med tabeller og kolonner, der har et Z foran navnet.
- Realm er en mobil database, som nogle apps bruger, med eget filformat.
- Protocol Buffers findes som binære felter inde i andre databaser og kræver kendskab til appens skema for at blive fortolket fuldt.
- Segmenterede logformater bruges af nyere iOS-funktioner til aktivitetsdata, se iPhone-artefakter.
- JSON-filer bruges af mange apps til konfiguration og cache.
Fælles for dem er, at en generel viser kan vise data, men ikke altid betydningen.
Sikring
- Sikr hele mappen med alle filer på én gang, helst fra en diskkopi eller et filsystemudtræk, så filerne svarer til samme øjeblik.
- Luk ikke appen og åbn den ikke for at “se efter”. Appen kan skrive, komprimere og rydde op.
- Beregn hashværdi for hver fil, og analysér kopier.
- Notér appens version, fordi formatet og felterne ændrer sig mellem versioner.
Fremgangsmåde ved analyse
- Identificér formatet ud fra filsignatur og mappestruktur, ikke ud fra filnavnet. En fil uden endelse kan være en binær plist, og en mappe med
CURRENTogMANIFESTer en LevelDB. - Afkod med et værktøj, der forstår formatet, og eksportér både rå værdier og fortolket visning.
- Kortlæg felternes betydning ved at sammenligne med appens brugerflade på et testsystem med samme version, fx ved at oprette en kendt besked eller ændre en indstilling og se, hvor det slår igennem.
- Gennemgå ældre versioner i LevelDB-loggen og ældre tabelfiler, og i backup og snapshots for plist-filer.
- Sammenhold med andre kilder, fx serverdata fra tjenesten eller tilsvarende data på en anden enhed.
Trin 3 er ofte det mest tidskrævende, men det er også det, der gør konklusionen efterprøvelig. Beskriv testene, så en anden kan gentage dem.
Typiske fejlkilder
- Gamle værdier som aktuelle. En værdi fundet i en ældre LevelDB-tabelfil kan være overskrevet for længe siden.
- Sekvensnummer som tid. Rækkefølge er ikke tidspunkt.
- Forkert epoke. Apples 2001-epoke forveksles med Unix-tid, og fejlen bliver 31 år.
- Ufuldstændig objektgraf. Et NSKeyedArchiver-objekt læst uden opløsning af henvisninger giver forkerte sammenhænge.
- Cache som brugerhandling. At data ligger i en apps lokale lager, viser ikke, at brugeren har set dem.
Hvad formaterne kan og ikke kan bevise
Plist og LevelDB kan vise indstillinger, tilstande og cachede data, og LevelDB kan desuden vise tidligere og slettede værdier. De kan understøtte en tidslinje, når værdierne indeholder tidsstempler. De kan sjældent alene vise, at en bestemt bruger har udført en bestemt handling, og tolkningen af appspecifikke felter skal altid begrundes.
I rapporten
Angiv sti, fil og hashværdi for hver kilde, appens version og den metode, værdierne er afkodet med. Gengiv nøgler og rå værdier sammen med fortolkningen, og beskriv, hvordan feltets betydning er fastlagt.
Kilder og versioner
- Apple Developer: PropertyListSerialization
- Google: LevelDB, implementering og filformat
- W3C: Indexed Database API
Senest gennemgået: oktober 2026.
Næste skridt
- Download dine data: platformenes udtræk som bevis
- ChatGPT, Claude og Gemini: historik og workspace-eksport
Del af: Analyse og fortolkning
Læs også: SQLite i forensic: WAL-filer, frie sider og slettede rækker · Browsercache, cookies og gemte sessioner som spor
→ Digital forensics-undersøgelse · For sagkyndige · Tlf. 70 13 63 23 · Digital bevissikring hos Nielco IT