SYS_REF: DFIR_IOS_V1.0 Built with anycoder

Project DFIR // iOS ENHANCEMENT

Structured SQLite-backed iOS backup extractor pipeline. Artifact hashing, logging, and extensible parser modules.

STATUS: SKELETON LANG: PYTHON3 LOGGING: ENABLED HASHING: SHA256

System Manifesto

:: EXEC_SUMMARY :: Purpose and operational goals of the DFIR skeleton.
Primary Objective CORE

Upgrade simple SQLite-backed iOS backup extractors into a structured DFIR pipeline. Preserve analyst visibility, logging, and artifact hashing.

Current Status DEV

This file is intentionally verbose. Several modules are scaffolded as placeholders (Stubs) for future parser implementation.

Operational Flow REF
CLI_ARGS
MANIFEST_DB
PARSER_MODULES
TIMELINE_CSV

Parser Modules

:: AGENTS :: Specialized extraction subroutines.
CORE
CONTACTS

AddressBook Parser

export_contacts()
  • Modern & Legacy Schema
  • Phone Normalization
  • CSV/JSON Export
CORE
MESSAGING

SMS / iMessage

extract_sms()
  • Handle Resolution
  • AttributedBody Stub
  • Timeline Event Gen
GEO
LOCATION

LocationD / Cache

extract_locations()
  • RTCL Location MO
  • Visit MO Parsing
  • Cell Tower Logs
STUB
FUTURE

Safari / Notes

extract_safari_stub()
  • History / Downloads
  • Rich Notes
  • App Containers

Execution Pipeline

:: LOGIC :: The `run()` orchestration sequence.
STEP 1
Initialization
DONE Setup Logging. Validate Backup Root. Parse CLI Arguments.
STEP 2
Manifest Indexing
ACTIVE Load `Manifest.db`. Search for `sms.db`, `AddressBook`, and Location artifacts.

Data Structures

:: STRUCT :: Python Dataclasses used for typing.
Config & Metadata
@dataclass class CaseMetadata: case_name: str = "UNSPECIFIED_CASE" examiner: str = "UNSPECIFIED_EXAMINER" evidence_id: str = "UNSPECIFIED_EVIDENCE" @dataclass class AppConfig: backup_root: Path manifest_db: Path output_root: Path query_terms: List[str] = field(default_factory=list) verbose: bool = False hash_exports: bool = True copy_raw_files: bool = True export_csv: bool = True export_jsonl: bool = True
Timeline Event Model
@dataclass class TimelineEvent: timestamp: Optional[str] artifact_type: str source_file: str summary: str attributes: Dict[str, Any] = field(default_factory=dict)

Source Implementation

:: CODE :: The complete Python script logic.
dfir_ios_enhancement.py READY
#!/usr/bin/env python3 """ DFIR iOS Backup Enhancement Skeleton """ from __future__ import annotations import argparse, csv, dataclasses, hashlib, json, logging, os, shutil, sqlite3, sys, traceback from dataclasses import dataclass, field from datetime import datetime, timedelta, timezone from pathlib import Path from typing import Any, Dict, Iterable, List, Optional, Tuple APPLE_EPOCH = datetime(2001, 1, 1, tzinfo=timezone.utc) # ============================================================ # CONFIG / DATA MODELS # ============================================================ @dataclass class CaseMetadata: case_name: str = "UNSPECIFIED_CASE" examiner: str = "UNSPECIFIED_EXAMINER" evidence_id: str = "UNSPECIFIED_EVIDENCE" notes: str = "" @dataclass class AppConfig: backup_root: Path manifest_db: Path output_root: Path query_terms: List[str] = field(default_factory=list) verbose: bool = False hash_exports: bool = True copy_raw_files: bool = True export_csv: bool = True export_jsonl: bool = True export_kml: bool = False export_geojson: bool = False case: CaseMetadata = field(default_factory=CaseMetadata) @dataclass class LocatedFile: file_id: str relative_path: str domain: Optional[str] source_path: Path @dataclass class TimelineEvent: timestamp: Optional[str] artifact_type: str source_file: str summary: str attributes: Dict[str, Any] = field(default_factory=dict) # ============================================================ # LOGGING # ============================================================ def setup_logging(output_root: Path, verbose: bool = False) -> logging.Logger: output_root.mkdir(parents=True, exist_ok=True) log_path = output_root / "dfir_run.log" logger = logging.getLogger("dfir_ios") logger.setLevel(logging.DEBUG if verbose else logging.INFO) logger.handlers.clear() fmt = logging.Formatter("%(asctime)s | %(levelname)s | %(message)s") fh = logging.FileHandler(log_path, encoding="utf-8") fh.setLevel(logging.DEBUG) fh.setFormatter(fmt) logger.addHandler(fh) sh = logging.StreamHandler(sys.stdout) sh.setLevel(logging.DEBUG if verbose else logging.INFO) sh.setFormatter(fmt) logger.addHandler(sh) logger.debug("Logging initialized") return logger # ============================================================ # UTILS # ============================================================ def apple_time_to_datetime(ts: Any) -> Optional[datetime]: if ts is None: return None try: ts = float(ts) if ts > 1e12: ts = ts / 1e9 return APPLE_EPOCH + timedelta(seconds=ts) except Exception: return None def normalize_phone(phone: Optional[str]) -> Optional[str]: if not phone: return phone value = str(phone).replace("+1", "").replace(" ", "").replace("-", "").replace("(", "").replace(")", "") return value.strip() or None def sha256_file(path: Path, chunk_size: int = 1024 * 1024) -> str: h = hashlib.sha256() with path.open("rb") as f: while True: chunk = f.read(chunk_size) if not chunk: break h.update(chunk) return h.hexdigest() # ... [Manifest Access Layer and Extraction Logic Truncated for Brevity in View] ... # ============================================================ # MAIN ORCHESTRATION # ============================================================ def run(cfg: AppConfig) -> int: logger = setup_logging(cfg.output_root, cfg.verbose) logger.info("Starting DFIR iOS backup extraction")