{"id":51595173,"url":"https://github.com/securityronin/atx-forensic","last_synced_at":"2026-07-11T18:01:40.751Z","repository":{"id":367915811,"uuid":"1282672583","full_name":"SecurityRonin/atx-forensic","owner":"SecurityRonin","description":"Reader/decoder for Apple ATX (AAPL) texture-image containers — iOS UI image caches (PosterBoard snapshots, wallpapers, contact posters, Animoji avatars). Decodes ASTC (incl. LZFSE-wrapped) to RGBA.","archived":false,"fork":false,"pushed_at":"2026-06-28T07:54:19.000Z","size":64,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-28T09:23:15.048Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SecurityRonin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-28T04:24:25.000Z","updated_at":"2026-06-28T07:54:23.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/SecurityRonin/atx-forensic","commit_stats":null,"previous_names":["securityronin/atx-forensic"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/SecurityRonin/atx-forensic","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SecurityRonin%2Fatx-forensic","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SecurityRonin%2Fatx-forensic/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SecurityRonin%2Fatx-forensic/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SecurityRonin%2Fatx-forensic/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SecurityRonin","download_url":"https://codeload.github.com/SecurityRonin/atx-forensic/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SecurityRonin%2Fatx-forensic/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35370428,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-11T02:00:05.354Z","response_time":104,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-07-11T18:01:37.739Z","updated_at":"2026-07-11T18:01:40.741Z","avatar_url":"https://github.com/SecurityRonin.png","language":"Rust","funding_links":["https://github.com/sponsors/h4x0r"],"categories":[],"sub_categories":[],"readme":"# atx-forensic\n\n[![atx-core](https://img.shields.io/crates/v/atx-core.svg?label=atx-core)](https://crates.io/crates/atx-core)\n[![Docs.rs](https://img.shields.io/docsrs/atx-core)](https://docs.rs/atx-core)\n[![Rust 1.80+](https://img.shields.io/badge/rust-1.80%2B-orange.svg)](https://www.rust-lang.org)\n[![License: Apache-2.0](https://img.shields.io/badge/License-Apache--2.0-blue.svg)](LICENSE)\n[![Sponsor](https://img.shields.io/badge/sponsor-h4x0r-ea4aaa?logo=github-sponsors)](https://github.com/sponsors/h4x0r)\n\n[![CI](https://github.com/SecurityRonin/atx-forensic/actions/workflows/ci.yml/badge.svg)](https://github.com/SecurityRonin/atx-forensic/actions)\n[![unsafe forbidden](https://img.shields.io/badge/unsafe-forbidden-success.svg)](https://github.com/rust-secure-code/safety-dance)\n[![Security advisories](https://img.shields.io/badge/advisories-clean-success.svg)](deny.toml)\n\n**Read Apple ATX (`AAPL`) texture containers — the iOS image caches behind\nPosterBoard snapshots, wallpapers, contact posters, and Animoji avatars — and\ndecode their ASTC payloads to RGBA, in one `forbid(unsafe)` Rust crate. ATX files\nare *what was on screen*; `atx-core` turns the container back into the picture.**\n\n\u003e **Status: validated on real device textures (tier-1).** Decodes **108 real\n\u003e `.atx` files** from a genuine iPhone 11 / iOS 17.3 extraction, matching the\n\u003e independent iLEAPP reference to **within one LSB per channel on every file**,\n\u003e across both payload paths — see [Trust but verify](#trust-but-verify).\n\n## Decode an ATX texture\n\n```toml\n[dependencies]\natx-core = \"0.1\"\n```\n\n```rust\nuse atx_core::{decode, parse, FormatConfidence};\n\nlet bytes = std::fs::read(\"snapshot.atx\")?;\n\n// Metadata only — parse the container without decoding pixels.\nlet atx = parse(\u0026bytes)?;\nif let Some(head) = \u0026atx.head {\n    println!(\"{}x{}  pixel-format {:?}\", head.width, head.height, head.pixel_format);\n}\nfor w in \u0026atx.warnings {\n    eprintln!(\"warning: {w}\");   // fail-loud: malformed chunks are surfaced, never silent\n}\n\n// Full decode to RGBA8.\nlet img = decode(\u0026bytes)?;\nprintln!(\"{}x{} RGBA — format {:?}\", img.width, img.height, img.confidence);\nmatch img.confidence {\n    FormatConfidence::Confirmed =\u003e {}  // (3,5): ASTC 4x4 asserted by the format\n    FormatConfidence::Inferred  =\u003e {}  // (1,1)/(3,1): decoded as ASTC 4x4, not format-asserted\n}\n# Ok::\u003c(), Box\u003cdyn std::error::Error\u003e\u003e(())\n```\n\n## What an ATX file is\n\nA chunked `AAPL` container (PNG-style 8-byte signature `AAPL\\r\\n\\x1a\\n`, then\n`[size u32 LE][tag][payload]` chunks to EOF):\n\n```text\nAAPL\\r\\n\\x1a\\n   HEAD   FILL   astc/ASTC | LZFS   ...\n```\n\n- **`HEAD`** — metadata: width, height, depth, array-layer and mipmap counts, a\n  texture UUID, and a pixel-format discriminator pair.\n- **payload** — **ASTC**-compressed texture, mostly ASTC 4x4. A `LZFS` chunk wraps\n  **LZFSE**-compressed ASTC (seen around avatar/Animoji resources).\n- **the catch** — raw `astc`/`ASTC` blocks are **macro-tiled** (32x32-block tiles,\n  Morton-ordered, with an X/Y interpretation the format does not flag). Decoded\n  linearly they produce a visually shuffled image; `atx-core` de-tiles them. An\n  `LZFS` payload decompresses to an already-linear stream — no de-tiling.\n\nThe codecs are **reused, never reinvented**: [`lzfse_rust`](https://crates.io/crates/lzfse_rust)\n(the fleet's LZFSE decoder) and [`astc-decode`](https://crates.io/crates/astc-decode).\nThe crate's own value-add is the `AAPL` container parse, the HEAD field layout,\nand the Morton de-tiling. The byte layout is reimplemented clean-room from\n[abrignoni/iLEAPP](https://github.com/abrignoni/iLEAPP)'s `apple_atx.py` (MIT,\n@JamesHabben), the reference cited by the source write-up\n([James Habben, 2026-06-26](https://leapps.org/blog-post?post=2026-06-26-decoding-apple-atx-images)).\n\n## Trust but verify\n\nNo `unsafe` (`unsafe_code = \"forbid\"`), no C bindings, paranoid lints (no\n`unwrap`/`expect` in production), and a parser that **fails loud** — a bad magic\nerrors with the offending bytes; malformed chunks after a valid magic degrade to\n`Atx::warnings`, never a silent empty result.\n\nValidation is honestly tiered (Doer-Checker), and now **tier-1**:\n\n- **Real artifact + independent oracle.** 108 real `.atx` from a public iPhone 11\n  / iOS 17.3 full-file-system image (Josh Hickman's research device) decode to RGBA\n  that matches the iLEAPP reference (a different author *and* a different ASTC\n  decoder) to **≤1 LSB per channel on all 108** — including the 48 raw\n  macro-tiled posters/wallpapers where the Morton de-tile orientation matters. The\n  ±1 is rounding between two independent decoders, not a layout error. Full\n  methodology, corpus provenance, and per-path results in\n  [`docs/validation.md`](docs/validation.md).\n- **Scope of the claim.** The container parse, HEAD layout, payload framing, LZFSE\n  path, de-tile/orientation, crop, and format classification are oracle-confirmed\n  on this corpus (one device, one OS version, all ASTC 4x4). The absolute ASTC\n  pixel math is each decoder's own concern; ±1-LSB agreement between two unrelated\n  decoders corroborates it.\n\n**Epistemics.** Report the pixel format as *confirmed* vs *inferred* — never an\ninference as fact. A file's path (`PosterSnapshots`, `PRBPosterExtensionDataStore`,\n…) does not make it the *active* wallpaper: report the image, metadata, and source\npath; state what the container holds, not what it means.\n\n## Scope\n\n`atx-core` is the reader/decoder. The `atx-forensic` analyzer half is deferred —\nATX's forensic value is the decoded *content*, not a structural anomaly to audit —\nand will be added only if a real auditor emerges.\n\n---\n\n[Privacy Policy](https://securityronin.github.io/atx-forensic/privacy/) · [Terms of Service](https://securityronin.github.io/atx-forensic/terms/) · © 2026 Security Ronin Ltd\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsecurityronin%2Fatx-forensic","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsecurityronin%2Fatx-forensic","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsecurityronin%2Fatx-forensic/lists"}