Skip to content

sujayadkesar/PhonePe-Forensics

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

12 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ” PhonePe Forensics

The definitive open-source DFIR toolkit for PhonePe iOS evidence extraction, cross-database correlation, and UPI fraud investigation


Blog Post Python Flask PRs Welcome DFIR UPI


"What Chitragupt records in mythology, PhonePe records in SQLite. This tool reads both."


How it looks!

Forensics Dashboard



Counterparty lookup



Transaction Ledger



Splunk like Hunting Dashboard


πŸ“‹ Table of Contents


🎯 What Is This?

PhonePe iOS Forensics is a full-spectrum digital forensics workstation β€” packaged as a local Flask web application β€” purpose-built for extracting, correlating, and presenting evidence from PhonePe iOS app acquisitions.

It turns a raw iOS backup or filesystem extraction into a structured, investigator-ready case:

Raw Acquisition Folder
        β”‚
        β–Ό
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚          PhonePe iOS Forensics Engine               β”‚
  β”‚                                                     β”‚
  β”‚  16 Extraction Modules  ──►  Correlation Engine     β”‚
  β”‚  50+ SQLite Databases   ──►  Unified Timeline       β”‚
  β”‚  15+ Plist Files        ──►  Social Graph           β”‚
  β”‚  Binary Cookies         ──►  PPQL Hunt Interface    β”‚
  β”‚  NSKeyedArchiver blobs  ──►  Suspicious Signals     β”‚
  β”‚  WebKit data            ──►  Multi-format Reports   β”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
        β”‚
        β–Ό
  Structured Evidence + Exportable Reports

This is not a wrapper around commercial tools. Every parser is written from scratch, specifically for PhonePe's internal SDK architecture β€” handling the real column names, real BLOB encodings, real timestamp epochs, and real database schemas that published forensic write-ups consistently get wrong.


πŸ’‘ Why It Matters

The Problem with Existing PhonePe Forensics

Virtually every publicly available PhonePe forensic reference makes the same category of mistakes:

Common Mistake Reality
References a ZTRANSACTION table with columns like ZAMOUNT, ZSENDERUPIID That table does not exist. The real table is ZTRANSACTIONENTITY
Reads amount directly from a column Amounts are packed inside a zlib-compressed JSON BLOB in ZDATA, in paise (not rupees)
Uses Unix epoch for all timestamps PhonePe iOS uses three different epochs interchangeably
Only reads the main AppDomain Critical databases (chat, contacts, P2P) live in AppDomainGroup β€” invisible to AppDomain-only extraction
Ignores WAL files Deleted records survive in SQLite WAL pages β€” critical for anti-tampering analysis

This tool fixes all of the above.

What the iOS App Actually Stores

Unlike server-side forensics (which requires legal process and is often delayed), the PhonePe iOS app locally preserves:

  • πŸ“Š Every transaction in a local SQLite ledger β€” including failed and abandoned payment attempts
  • πŸ‘₯ Every contact with their UPI IDs and cached profile photos
  • πŸ’¬ In-app chat messages with bidirectional links to financial transactions
  • πŸ“² Sub-second behavioral logs of every tap, screen view, and keyboard entry
  • πŸ”” Push notification payloads that survive even after transaction deletion
  • ✈️ Physical travel data including PNR numbers, passenger identities, and co-traveler names
  • πŸ€– ML-inferred financial patterns that persist even after transaction deletion
  • 🏦 AutoPay mandates (active and revoked) invisible in the current app UI

πŸ—οΈ Architecture

phonepe_forensics/
β”œβ”€β”€ core.py           ← Parsing primitives (SQLite/WAL, plist, binarycookies,
β”‚                       NSKeyedArchiver, timestamp normalization, hashing)
β”‚
β”œβ”€β”€ extractors.py     ← 16 forensic extraction modules
β”‚                       (identity, transactions, contacts, chat, notifications,
β”‚                        analytics, financial, travel, payment_infra, config_state,
β”‚                        recommendations, media, search, webkit, audit, app_state)
β”‚
β”œβ”€β”€ correlator.py     ← Cross-database fusion engine
β”‚                       (unified_timeline, social_graph, counterparty_profiles,
β”‚                        corroboration_index, suspicious_signal_detection)
β”‚
β”œβ”€β”€ hunt.py           ← PPQL β€” PhonePe Query Language parser & executor
β”‚                       (SPL-inspired query engine over merged forensic indexes)
β”‚
β”œβ”€β”€ case.py           ← Case orchestrator
β”‚                       (coordinates extraction, caches results, exposes to UI)
β”‚
β”œβ”€β”€ case_manager.py   ← Multi-case registry
β”‚                       (JSON-manifest backed, persist across restarts)
β”‚
β”œβ”€β”€ reports.py        ← Report exporter
β”‚                       (CSV, JSON, HTML β€” self-contained, no external deps)
β”‚
β”œβ”€β”€ research_data.py  ← In-app reference documentation
β”‚                       (every artifact, schema, and query β€” built-in)
β”‚
β”œβ”€β”€ webapp.py         ← Flask web UI (35+ routes, multi-case, full UI)
β”‚
β”œβ”€β”€ templates/        ← Jinja2 HTML templates
└── static/           ← CSS + JS

Design Principles

  • Defensive parsing everywhere β€” all parsers degrade gracefully on partial corruption, because forensic acquisitions frequently contain truncated or partially checkpointed databases
  • WAL-aware by default β€” SQLite opened in mode=ro&cache=private, WAL contents automatically applied on open, uncommitted-but-checkpointed transactions are visible
  • Zero writes to evidence β€” never touches the source folder; all processing is read-only
  • Multi-epoch timestamp normalization β€” every timestamp column is automatically detected and normalized across Unix-ms, Unix-s, and Apple CoreData epochs
  • BLOB auto-detection β€” ZDATA blobs are tried as raw JSON, then zlib-compressed JSON, then NSKeyedArchiver plist, before graceful fallback

⚑ Quick Start

# 1. Clone
git clone https://github.com/thelocalh0st/phonepe-ios-forensics.git
cd phonepe-ios-forensics

# 2. Install
pip install flask

# 3. Launch
python run.py

# Opens http://127.0.0.1:5000 in your browser automatically

That's it. No config files. No API keys. No database setup. Open the Case Manager, point it at your acquisition folder, and click Process Case.


πŸ“¦ Installation

Requirements

Component Minimum
Python 3.9+
Flask 2.x
OS Windows Β· macOS Β· Linux
Disk Enough for your acquisition + ~50MB working space

Standard Install

pip install flask

Flask is the only hard dependency. The tool uses Python's stdlib for everything else: sqlite3, plistlib, hashlib, struct, zlib, re, json, csv.

Optional (recommended for development)

pip install flask werkzeug

Virtual Environment (recommended)

python -m venv venv
source venv/bin/activate        # Linux / macOS
venv\Scripts\activate.bat       # Windows

pip install flask
python run.py

Windows-Specific Notes

On Windows, the entry point auto-configures UTF-8 encoding for stdout/stderr β€” no manual chcp 65001 needed:

# run.py handles this automatically
os.environ.setdefault("PYTHONIOENCODING", "utf-8")
sys.stdout.reconfigure(encoding="utf-8")

🧭 Usage

Starting the Server

# Default (127.0.0.1:5000)
python run.py

# Custom host:port
python run.py 0.0.0.0:8080

# Or as a module
python -m phonepe_forensics.webapp 127.0.0.1:5000

πŸ”’ Security Note: The server binds to 127.0.0.1 by default. Do not expose to a network interface in a multi-user environment β€” this is a single-investigator local workstation tool.

Creating a Case

Navigate to Case Manager β†’ New Case. Two input modes are supported:

Mode 1 β€” Single Root Folder (most common)

Point to the parent directory that contains all three AppDomain* containers:

/path/to/extraction/
β”œβ”€β”€ AppDomain-com.phonepe.PhonePeApp/
β”œβ”€β”€ AppDomainGroup-group.com.phonepe.PhonePeApp/
└── AppDomainGroup-group.com.phonepe.shared/

Mode 2 β€” Three-Folder Mode (split exports)

Explicitly point each of the three containers at a separate path β€” useful when an investigator has received partial exports from different acquisition sources.

Processing a Case

After creation, click Process Case to run all 16 extraction modules sequentially. Processing is fully parallelism-safe β€” each module reads independently. Typical processing time on a full acquisition: 5–30 seconds depending on database sizes.

Results are cached in memory and available immediately across all views.

Navigating Evidence

The left sidebar provides one-click access to every evidence category:

View What You See
🏠 Dashboard Summary cards β€” transaction count, contact count, chat groups, findings
πŸ‘€ Identity Registered name, UPI ID, device fingerprints, session tokens, location hints
πŸ’Έ Transactions Full ledger with filtering by date, direction, state, amount, counterparty
πŸ‘₯ Contacts Cyclops-verified contacts + phonebook with UPI ID resolution
🌐 Social Graph Contact ↔ transaction ↔ chat linkage visualization
πŸ’¬ Chat Burble group messages with linked transaction cards
πŸ”” Notifications PubSubCore push topic archive
πŸ“Š Analytics Foxtrot + KN + Dash behavioral event batches
πŸ’° Financial Rewards, mutual funds, vouchers, donations
✈️ Travel Yatra booking PNRs, passenger names, co-travelers
🏦 Payment Infra Linked banks, UPI VPAs, payment instruments, AutoPay mandates
βš™οΈ Config State Chimera remote config, A/B test assignments, feature flags
🎯 Recommendations Maximus offers engine + Athena ML signals
πŸ–ΌοΈ Media QR code artifacts, transaction backgrounds, profile photos
πŸ” Search AppSearch FTS query history + NexusCore sitemap
🌐 WebKit ResourceLoadStatistics + binary cookies
πŸ•΅οΈ Audit Chitragupt + Chronicle + Samsara + sync gap analysis
⏱️ Timeline Unified chronological event stream across all databases
🚨 Findings Heuristic suspicious signal flags
πŸ—„οΈ DB Browser Raw SQL interface against any parsed database
πŸ”Ž Hunt (PPQL) PhonePe Query Language search interface
πŸ“– Research Built-in artifact reference documentation

πŸ“ Evidence Modules β€” 16 Parsers

Each module is a self-contained extractor that reads from specific databases and plists within the three storage domains.

πŸͺͺ extract_identity

Pins the ownership of the device + UPI account. Sources:

  • com.phonepe.widgetxii.datacache.plist β†’ primary UPI ID
  • com.phonepe.help.customDataStore.plist β†’ userName + refreshToken
  • com.phonepe.ads.sdk.plist β†’ GPS coordinates, pincode, state
  • com.apple.AdSupport.plist β†’ IDFA enforcement state
  • com.firebase.FIRInstallations.plist β†’ Firebase install ID
  • __gads__.plist β†’ Google Ads signals
  • com.phonepe.PhonePeApp.plist (222 keys) β†’ session IDs, BoltV2 token preview, Chimera quick-flags

Forensic Output:

registered_name     β†’ KYC-verified legal name
upi_id              β†’ Primary UPI VPA
phones_seen         β†’ All phone numbers extracted from any source
device_identifiers  β†’ AppsFlyer, Firebase, GADS, AdSupport IDs
location_hints      β†’ [{ lat, lng, pincode, state, source }]
tokens              β†’ Help refresh token, optimus token, BoltV2 preview
sessions            β†’ Token expiry, fetch timestamps
feature_flags       β†’ Active Chimera quick-flags

πŸ’Έ extract_transactions

Master ledger parser β€” the highest-value module. Reads TransactionsStore.sqlite with full ZDATA blob decoding.

TransactionsStore.sqlite
β”œβ”€β”€ ZTRANSACTIONENTITY      ← one row per transaction
β”‚   └── ZDATA               ← zlib-compressed JSON with the actual payload
β”œβ”€β”€ ZTRANSACTIONTAGENTITY   ← ~4 tags per transaction (payment_source, utr, etc.)
β”œβ”€β”€ ZVIEWENTITY             ← display-optimized mirror (survives ZDATA corruption)
β”œβ”€β”€ ZUSER                   ← device owner (1 row)
└── ZTRANSACTIONSEARCHRECENTS ← user's own search queries in transaction history

The ZDATA blob is automatically decoded through a waterfall:

  1. Raw JSON
  2. zlib.decompress() β†’ JSON
  3. NSKeyedArchiver plist
  4. Graceful hex preview fallback

Amount unit detection handles the paise trap automatically: "value": 50000, "unitType": "PAISA" β†’ β‚Ή500.00.

Transaction ID Embedded Timestamp Decoding: PhonePe transaction IDs embed a timestamp in their structure (e.g., T2412190843728...). The tool decodes this as an independent timestamp source β€” useful for detecting clock manipulation.


πŸ‘₯ extract_contacts

Reads SamparkV2.sqlite (group container) β€” PhonePe's proprietary contact intelligence system.

SCONTACT                   β†’ Phone β†’ UPI ID β†’ name mapping (financial social graph)
SCONTACT_UPI_MAPPING       β†’ Historical phone-to-VPA associations with timestamps
ZPHONEBOOKCONTACT          β†’ Raw device address book (with deletion flags)

Key forensic outputs:

  • Name divergence detection β€” SDISPLAY_NAME (PhonePe's view) vs SDEVICE_CONTACT_NAME (phonebook) β€” reveals contact renaming used to obscure payment recipients
  • Transaction frequency scores β€” SLAST_TRANSACTED_AT + STRANSACTION_COUNT independent of TransactionsStore
  • Profile photo recovery from .SamparkV2_SUPPORT/_EXTERNAL_DATA/ β€” photos persist after contact deletion

πŸ’¬ extract_chat

Parses BurbleNotificationStore.sqlite β€” the in-app P2P chat + payment notification system.

ZBURBLEGROUP          β†’ Group containers with subscriber lists
ZBURLBEMESSAGE        β†’ Individual messages (TEXT, PAYMENT_INFO_CARD, REWARD_CARD)
ZBANKACCOUNTCONTACT   β†’ Shared bank account disclosures (account + IFSC + VPA)

Every PAYMENT_INFO_CARD message embeds: amount, UPI reference, instrument, UTR, payment state β€” creating a second independent transaction record inside the chat layer.


πŸ”” extract_notifications

Reads PubSubCoreBullhornDataStore.sqlite β€” the most tamper-resistant evidence source in the corpus.

Push notification payloads arrive from PhonePe's servers before any user interaction is possible. A user can delete a transaction from TransactionsStore. They cannot retroactively delete the push notification. The payload:

{
  "transactionId": "T241119182327",
  "amount": "500",
  "sender": "rahul@phonepe",
  "status": "SUCCESS",
  "bankRefNo": "401234567890",
  "timestamp": "2024-11-19T18:23:27+05:30"
}

...is a server-pushed attestation of a successful transaction, logged independently of any user-controlled record.


πŸ“Š extract_analytics

Three sub-sources:

Foxtrot (FoxtrotEventsDB.sqlite β€” group container): PhonePe's analytics batching pipeline. The critical distinction:

FUPLOAD_STATUS = 'UPLOADED'  β†’  Server-side records exist β€” obtainable via legal process
FUPLOAD_STATUS = 'PENDING'   β†’  EXCLUSIVELY local evidence β€” cannot be obtained via legal process

Events inside pending batches include geolocation coordinates: {"latitude": 17.385, "longitude": 78.486} β€” location data tied to transactions even when no explicit location column exists.

KN Analytics (kn_analytics_db.sqlite): Content interaction log β€” proves which merchants/offers a user was exposed to and clicked on before any payment.

Dash (Dash-Events.sqlite): Screen load latencies β€” implicitly prove specific screens were rendered at specific timestamps.


πŸ’° extract_financial

Parses rewards, mutual funds, vouchers, and donations:

  • RewardsDataStore.sqlite β€” scratch cards with ZLINKED_TXN_ID β†’ independent transaction corroboration
  • MFDataStore.sqlite β€” portfolio holdings + SIP mandates
  • BrandVouchersDataStore.sqlite β€” merchant-specific spending patterns (Swiggy, Zomato, Amazon...)
  • DonationsDataStore.sqlite β€” NGO payments, PM-CARES contributions
  • OffersDataStore.sqlite β€” merchant offers shown and clicked, timestamped

Scratch card forensic significance: A scratch card is server-issued only on transaction success. Its existence independently proves the transaction completed β€” even if the ZTRANSACTIONENTITY row was deleted.


✈️ extract_travel

Reads YatraDataModel.sqlite β€” a physical movement artifact.

ZBOOKING       β†’ Route, journey date, PNR, booking timestamp, amount
ZPASSENGER     β†’ Legal name, age, ID proof type, ID proof number (Aadhaar/Passport)

ZID_PROOF_NUMBER is a direct Aadhaar or passport number. Co-passenger records prove physical co-location with named associates. PNR cross-reference with IRCTC/airline records builds a travel timeline that corroborates or contradicts alibi claims.

Transaction Background Date Decoding: Folder names in P2P/TransactionBackgrounds/ embed the download date. The oldest folder = earliest PhonePe activity on this device. This survives complete transaction history deletion.


🏦 extract_payment_infra

Comprehensive payment infrastructure mapping:

AccountSharedDataModel.sqlite
β”œβ”€β”€ ZUSERPROFILE        β†’ KYC identity, Aadhaar/PAN link status
β”œβ”€β”€ ZLINKEDBANKACCOUNT  β†’ All banks ever linked (including delinked with ZDELINKED_AT)
└── ZUPIID              β†’ All VPAs (active + deregistered)

PaymentDataStore.sqlite
β”œβ”€β”€ ZPAYMENTINTENTENTITY    β†’ "Ghost transactions" β€” initiated but never completed
β”œβ”€β”€ ZPAYMENTGATEWAYRESPONSE β†’ Raw bank gateway responses with NPCI trace IDs
β”œβ”€β”€ ZUPILINKEDACCOUNT       β†’ VPA-to-bank-account binding records
└── ZAUTOPAYMANDATE         β†’ AutoPay mandates β€” including REVOKED with revoked_at

Delinked bank accounts (ZDELINKED_AT not null) are invisible in the current UI but fully preserved β€” historically linked financial instruments that may have been removed shortly before investigation.

Ghost transactions β€” ZPAYMENTINTENTENTITY rows created the instant a user initiates a payment flow, before any UPI call is made. Even if the user cancels after entering the amount, this record exists. Destroys "I never tried to send that amount" claims.


βš™οΈ extract_config_state

Reads Chimera's remote config cache and A/B test assignments:

ChimeraCoreResponseStore.sqlite β†’ Exact UI specs served to this device at each timestamp
ExperimentationCoreStore.sqlite β†’ Which A/B test variant the user was actually shown
ConfigManagerKeyStore.sqlite    β†’ API endpoints, transaction limits, fraud detection toggles

If a defense argument is "the payment screen was confusing/misleading," Chimera's cache is the evidentiary record of the exact UI the user saw at that time β€” pinned to a specific server deployment version.


🎯 extract_recommendations

  • MaximusDataModel.sqlite β€” promotions and offer engine state
  • AthenaStore.sqlite β€” on-device ML recommendation model outputs and signals

πŸ–ΌοΈ extract_media

  • QR code artifacts β€” downloaded QR images with merchant embeddings
  • Transaction backgrounds β€” PNG card assets with encoded download dates (first-use dating)
  • Profile photos β€” contact display pictures from _EXTERNAL_DATA/

πŸ” extract_search

  • AppSearch FTS recents β€” user's in-app search queries
  • NXCoreDataStore.sqlite β€” NexusCore mini-app sitemap

🌐 extract_webkit

  • ResourceLoadStatistics β€” website interaction history
  • Cookies.binarycookies β€” Apple binary cookie format, fully decoded:
class BinaryCookieReader:
    # Parses Apple's proprietary binary cookie format
    # Header: "cook" magic + page count
    # Per-page: offset table β†’ cookies with flags, domain, name, value, path, expiry

πŸ•΅οΈ extract_audit

Multi-source audit reconstruction:

  • Chitragupt β€” sub-second UI behavioral log (tap β†’ keyboard β†’ screen β†’ mPIN confirm)
  • Chronicle β€” app timeline feed (orphaned references prove deleted transactions existed)
  • Samsara β€” UPI payment state machine transitions (INITIATED β†’ PROCESSING β†’ SUCCESS)
  • BGFramework β€” background task execution log (proves device was active at specific times)
  • CentralSyncManager β€” sync gap analysis (uniform gap = offline period, seizure, or tampering)
  • AuthDataModel β€” login history with success/failure flags and failure reasons

KEYBOARD events in Chitragupt prove an amount was typed manually (not auto-filled). The mpin_confirm TAP event proves the user explicitly authorized a payment. Together, these are the most powerful anti-repudiation evidence in the corpus.


πŸ—„οΈ Supported Artifacts β€” The Full Map (50+ Databases)

AppDomain-com.phonepe.PhonePeApp/Documents/

Database SDK Forensic Role
TransactionsStore.sqlite Core Financial Master UPI transaction ledger
PaymentDataStore.sqlite Payment Engine In-flight payment state, ghost transactions, AutoPay mandates
TransferDataStore.sqlite Transfer SDK Recent payees, collect requests, payment frequency map
AccountSharedDataModel.sqlite Account SDK KYC identity, linked banks (including delinked), UPI VPAs
AuthDataModel.sqlite Auth SDK Session tokens, device binding, login history
Consent.sqlite Privacy SDK Consent grants and revocations with timestamps
CustodianPrivacy.sqlite Privacy SDK Data protection policy acceptance log
ChatPlatform.sqlite Chat SDK P2P conversation threads with transaction links
PubSubCoreBullhornDataStore.sqlite PubSub SDK Push notification payload archive (tamper-resistant)
ChimeraCoreResponseStore.sqlite Chimera / LiquidUI Remote UI config + feature flag cache
ExperimentationCoreStore.sqlite Experimentation A/B test variant assignments
ConfigManagerKeyStore.sqlite ConfigManager API endpoints, limits, fraud toggle state
ChimeraCoreResponseStore.sqlite (LiquidUI path) LiquidUI Screen definition cache
Chitragupt.sqlite Chitragupt Full behavioral audit ledger (sub-second)
Chronicle.sqlite Chronicle App timeline + notification history
Dash-Events.sqlite Dash Performance metrics (screen render timestamps)
kn_analytics_db.sqlite KN Analytics Content/merchant interaction log
BGFrameworkDataModel.sqlite BGFramework Background task execution log
CentralSyncManager.sqlite Sync Cross-module sync gap analysis
SamsaraDataStore.sqlite Samsara UPI payment state machine transitions
AthenaStore.sqlite Athena On-device ML recommendation engine
Cassini.sqlite Cassini Document classification (KYC/QR)
MaximusDataModel.sqlite Maximus Promotions and offer engine
NXCoreDataStore.sqlite NexusCore Mini-app catalogue + sitemap
MFDataStore.sqlite Mutual Funds Portfolio holdings + SIP mandates
RewardsDataStore.sqlite Rewards Scratch cards β†’ independent transaction proof
BrandVouchersDataStore.sqlite Brand Vouchers Merchant-specific spending patterns
DonationsDataStore.sqlite Donations NGO/charity payment records
OffersDataStore.sqlite Offers Merchant offer exposure + click timestamps
YatraDataModel.sqlite Yatra Travel bookings + passenger PII + PNR
PrepaidRechargeDataStore.sqlite Recharge Mobile/DTH recharge history + saved numbers
CRMDataModel.sqlite CRM Support ticket transcripts + user-authored dispute text
Pratikriya.sqlite Pratikriya User ratings + free-text feedback linked to transaction IDs
Gravity.sqlite Gravity Feed/discovery ranking state

AppDomainGroup-group.com.phonepe.PhonePeApp/

Database Forensic Role
P2P.sqlite Split-bill groups, expenses, money requests, payment backgrounds
SamparkV2.sqlite Financial social graph β€” phone β†’ UPI ID β†’ name β†’ profile photo
FoxtrotEventsDB.sqlite Analytics upload queue (PENDING = exclusively local evidence)

AppDomain-com.phonepe.PhonePeApp/Library/

Artifact What It Contains
Preferences/com.phonepe.PhonePeApp.plist 222 keys β€” session IDs, BoltV2 token, Chimera flags
Preferences/com.phonepe.widgetxii.datacache.plist Primary UPI ID (home page cache)
Preferences/com.phonepe.help.customDataStore.plist Registered name + auth tokens
Preferences/com.phonepe.ads.sdk.plist GPS coordinates, pincode, state
Preferences/com.phonepe.account.plist Token expiry + fetch timestamps
Preferences/com.apple.AdSupport.plist IDFA enforcement
Preferences/com.firebase.FIRInstallations.plist Firebase install ID
Preferences/__gads__.plist Google Ads signals
Cookies/Cookies.binarycookies Apple binary cookie format β€” decoded session cookies
WebKit/ResourceLoadStatistics/ Website interaction history

πŸ§ͺ The Three Storage Domains

PhonePe iOS sandboxes evidence across three containers with different trust boundaries. Missing any one domain means missing evidence.

iOS Filesystem
β”‚
β”œβ”€β”€ AppDomain-com.phonepe.PhonePeApp/
β”‚   β”œβ”€β”€ Documents/          ← Core app databases (Transactions, Auth, Chat...)
β”‚   └── Library/
β”‚       β”œβ”€β”€ Preferences/    ← 15+ plist files (identity, tokens, location)
β”‚       β”œβ”€β”€ Cookies/        ← Cookies.binarycookies
β”‚       └── WebKit/         ← ResourceLoadStatistics, offline storage
β”‚
β”œβ”€β”€ AppDomainGroup-group.com.phonepe.PhonePeApp/
β”‚   └── com.phonepe.PhonePeApp/
β”‚       β”œβ”€β”€ P2P/            ← P2P.sqlite (split bills, money requests)
β”‚       β”œβ”€β”€ SamparkV2/      ← SamparkV2.sqlite + profile photo BLOBs β¬… MOST CRITICAL
β”‚       └── FoxtrotEventsStore/  ← FoxtrotEventsDB.sqlite
β”‚
└── AppDomainGroup-group.com.phonepe.shared/
    └── Library/Preferences/    ← Cross-process shared state

⚠️ Critical: Many investigations only include AppDomain. Without the group containers, chat history, contact graph, and recent UPI events are unrecoverable β€” they are physically stored in the group sandbox. Always verify all three containers are present before drawing conclusions.

Acquisition Priority

1. Full filesystem (jailbroken / GrayKey / Cellebrite Premium)
   β†’ All three containers + WAL files + free pages + temp files

2. Advanced Logical / AFC2 (jailbroken)
   β†’ AppDomain + AppDomainGroup accessible

3. iTunes Encrypted Backup
   β†’ AppDomain manifest-based; requires backup password

4. iTunes Unencrypted Backup
   β†’ Limited; some fields protected by iOS Data Protection

WAL File Analysis β€” Never Skip This

TransactionsStore.sqlite      ← committed, checkpointed data
TransactionsStore.sqlite-wal  ← recent uncommitted changes ← CRITICAL
TransactionsStore.sqlite-shm  ← shared memory WAL index

SQLite in WAL mode writes changes to the -wal file first. Deleted records are not immediately removed β€” they remain in WAL or free pages until SQLite reuses storage. The tool opens all databases in mode=ro&cache=private β€” WAL contents are automatically applied.

⚠️ Never run PRAGMA wal_checkpoint(TRUNCATE) on evidence. It destroys WAL contents and with them any recoverable deleted records.


πŸ”Ž PPQL β€” PhonePe Query Language

PPQL is a small, deterministic SPL-inspired query language built into the Hunt interface. Issue fast filters and aggregations across merged forensic indexes without writing SQL.

Grammar

QUERY    := SOURCE PIPE_OP*
SOURCE   := "search" STRING       -- full-text across the merged index
          | "from" INDEX          -- use a specific index
          | INDEX                 -- alias for "from <index>"
PIPE_OP  := "|" CMD ARG*
CMD      := "where" CONDITION
          | "search" STRING       -- second-stage full-text filter
          | "sort"  FIELD ["asc"|"desc"]
          | "head" N | "tail" N | "limit" N
          | "table" FIELD ("," FIELD)*
          | "top" N FIELD
          | "rare" N FIELD
          | "stats" AGG ("by" FIELD)?
          | "dedup" FIELD
          | "rename" FIELD "as" FIELD
AGG      := "count" | "sum(" FIELD ")" | "avg(" FIELD ")"
          | "min(" FIELD ")" | "max(" FIELD ")"

Available Indexes

Index Description
transactions Master ledger β€” ZTRANSACTIONENTITY
contacts PhonePe-verified Cyclops contacts
phonebook Raw device address book
chat_groups Burble group containers
chat_messages Individual chat messages
notifications PubSub push topic archive
timeline Unified chronological event stream

Example Queries

Find all outgoing transactions over β‚Ή5,000 and sort by amount:

transactions
  | where direction = "OUT" and amount_inr > 5000
  | sort amount_inr desc
  | head 50
  | table created_at, counterparty, amount_inr, utr

Reconstruct a specific phone number's payment history:

transactions
  | where counterparty_phone = "9876543210"
  | stats count by state

Find all senders in chat who match a partial masked number:

chat_messages
  | where sender_phone_masked like "*6259"
  | stats count by sender_name

Top 10 regions of PhonePe contacts:

contacts
  | where on_phonepe = true
  | top 10 region

Regex match β€” find transactions to merchants containing "Bharath":

transactions
  | where counterparty matches "[Bb]harath.*"
  | stats sum(amount_inr) by counterparty

Timeline after a specific date from Burble:

timeline
  | where source = "Burble" and when_iso > "2025-01-01"
  | head 200

Full-text search across all indexes:

search "UTR401234567890"
search "UTR" | where amount_inr > 1000

Find failed transactions in a date range:

transactions
  | where state = "FAILED"
  | where created_at_iso > "2024-01-01" and created_at_iso < "2024-12-31"
  | sort created_at_iso desc
  | table created_at_iso, counterparty, amount_inr, response_code

πŸ•ΈοΈ Cross-Database Correlation Engine

correlator.py fuses evidence from all 16 modules into investigation-grade artifacts.

build_unified_timeline

Merges every timestamped event across every module into one chronological stream. Sources fused:

TransactionsStore    β†’ UPI transaction events
Burble               β†’ Chat messages + payment cards
PubSubCore           β†’ Push notification arrivals
Foxtrot              β†’ Analytics batch uploads
Chitragupt           β†’ UI behavioral events (taps, keyboard, screen views)
Chronicle            β†’ App timeline + notification history
Samsara              β†’ UPI state machine transitions
Yatra                β†’ Travel booking timestamps
Analytics            β†’ KN content interactions
Recommendations      β†’ ML signal timestamps

Each event carries: { when_ms, when_iso, source, kind, title, detail, link_id?, amount_inr? }

build_social_graph

Builds a counterparty-centric social graph by fusing:

  • Contacts (SamparkV2) β€” who is in the phonebook + UPI IDs
  • Transactions (TransactionsStore) β€” who money moved to/from
  • Chat (Burble) β€” who messages were exchanged with

Output: per-counterparty summary with transaction count, total amount, chat message count, shared groups, and last interaction timestamp.

build_counterparty_profile

Given any identifier (phone, VPA, or name), produces a comprehensive dossier:

  • All transactions (in + out)
  • All chat interactions
  • Contact record details
  • Financial relationship metrics
  • Timeline of interactions

build_corroboration_index

For each transaction ID, maps every database that references it:

Transaction T241119182327:
  βœ“ TransactionsStore    β†’ ZTRANSACTIONENTITY row
  βœ“ RewardsStore         β†’ ZSCRATCH_CARD with ZLINKED_TXN_ID
  βœ“ PubSubCore           β†’ Push notification payload
  βœ“ Chronicle            β†’ Timeline item (even if TransactionsStore row deleted)
  βœ“ Burble               β†’ Chat PAYMENT_INFO_CARD

Corroboration Score: 5/5 β€” cannot be disputed as non-existent

A score of 1 with the single source being outside TransactionsStore is a red flag β€” it means a transaction ID exists in satellite evidence but the master ledger row is missing (possible deletion).


⏱️ Unified Timeline & Suspicious Signal Detection

Heuristic Signal Categories

The detect_suspicious_signals function produces investigator flags:

Signal Severity Trigger
High deletion intensity πŸ”΄ High freelist_count / page_count > 0.20 in transactions/contacts/chat DB
Failed/pending transactions 🟑 Medium Any FAILED, PENDING, or REJECTED transactions
High-value transactions πŸ”΅ Info Any success transaction β‰₯ β‚Ή50,000
Analytics upload failures πŸ”΅ Info Foxtrot events with β‰₯ 3 failed upload retries
Uncorroborated transaction IDs 🟑 Medium TXN IDs visible in satellite DBs but absent from TransactionsStore
Wallet balance present πŸ”΅ Info eGV wallet balance > 0 (relevant to investigation scope)

Deletion Intensity Analysis

-- Quick deletion check on any database
PRAGMA freelist_count;   -- Pages on freelist (deleted rows)
PRAGMA page_count;       -- Total pages

-- > 20% = active deletion β€” flag in report

The tool automatically runs this check and flags databases where deletion intensity suggests evidence tampering.


🧩 Timestamp Semantics β€” The Three Epochs

The most common error in published PhonePe forensic write-ups. PhonePe iOS uses three timestamp formats interchangeably.

Value Range Epoch Example Conversion
~400M – 950M Apple CoreData (+ 978,307,200) 721,692,800 β†’ Nov 14, 2023 ts + 978307200
~1.4B – 1.8B Unix seconds 1,700,000,000 β†’ Nov 14, 2023 Direct
~1.4T – 1.8T Unix milliseconds (Γ· 1000) 1,700,000,000,000 β†’ Nov 14, 2023 ts / 1000

The tool's normalize_timestamp() function auto-detects the epoch by value range:

def normalize_timestamp(value: Any) -> Optional[Dict[str, Any]]:
    v = float(value)
    if v > 1e12:          # Unix milliseconds
        epoch_s = v / 1000.0
    elif v > 1e9:         # Unix seconds
        epoch_s = v
    elif NSDATE_REASONABLE_MIN < v < NSDATE_REASONABLE_MAX:
        epoch_s = v + APPLE_EPOCH_OFFSET   # CoreData
    # Returns { epoch_ms, iso, display, source }

Every extracted timestamp is returned as { epoch_ms, iso, display, source } β€” the source field tells you which epoch was detected, so you can audit the conversion.

⚠️ A single miscategorized epoch shifts every date in the case by 31 years. Always verify the epoch before reporting dates.


πŸ“€ Export Formats

All exports are available from the Exports page or per-view download buttons.

CSV Exports (per evidence type)

File Contents
transactions.csv Full ledger β€” all decoded fields including counterparty, UTR, amount
contacts_phonepe.csv Cyclops contacts with UPI IDs
contacts_phonebook.csv Raw device phonebook
chat_groups.csv Burble group metadata
chat_messages.csv All messages with linked transaction IDs
chat_shared_contacts.csv Bank account disclosures shared in chat
linked_accounts.csv All bank accounts ever linked
linked_cards.csv All payment cards
timeline.csv Full unified timeline
findings.csv Suspicious signal flags
social_graph.csv Contact ↔ transaction relationship map

JSON Export

Structured master JSON of the complete case β€” all modules, all correlation outputs, all metadata β€” suitable for integration with other DFIR tooling.

HTML Report

Self-contained, single-file HTML evidence report with no external dependencies β€” fully renderable offline. Suitable for court submission or sharing with legal teams.


πŸ”¬ Research Reference

The Research tab inside the tool contains built-in reference documentation for every artifact β€” no internet required:

1. Architecture Overview        β†’ Storage domains, acquisition hierarchy, SDK map
2. Core Financial DBs           β†’ TransactionsStore, PaymentDataStore, P2P
3. Identity & Auth DBs          β†’ AccountSharedDataModel, AuthDataModel
4. Social Graph                 β†’ SamparkV2 schema, profile photo recovery
5. Chat & Notifications         β†’ ChatPlatform, PubSubCore
6. Behavioral Analytics         β†’ Chitragupt, Foxtrot, Dash, Chronicle
7. Server Config & A/B Testing  β†’ Chimera, ExperimentationCore, ConfigManager
8. Financial Services           β†’ MF, Rewards, Vouchers, Donations, Offers
9. Travel & Recharge            β†’ Yatra, PrepaidRecharge
10. Infrastructure              β†’ BGFramework, CentralSyncManager, Samsara
11. Specialty DBs               β†’ Pratikriya, CRM, Gravity, Cassini
12. Plist Files                 β†’ All 15+ plists with field-level documentation
13. WebKit & Cookies            β†’ Binary cookie format, ResourceLoadStatistics
14. Timestamp Reference         β†’ Three epochs, conversion formulas, detection guide
15. Corroboration Framework     β†’ Cross-DB evidence matrix
16. Query Arsenal               β†’ 30+ ready-to-run PPQL queries

πŸ—‚οΈ Project Structure

phonepe-ios-forensics/
β”‚
β”œβ”€β”€ run.py                          ← Entry point
β”‚
β”œβ”€β”€ phonepe_forensics/
β”‚   β”œβ”€β”€ __init__.py                 ← Package init, version
β”‚   β”œβ”€β”€ core.py                     ← Parsing primitives
β”‚   β”œβ”€β”€ extractors.py               ← 16 extraction modules (~2,200 lines)
β”‚   β”œβ”€β”€ correlator.py               ← Correlation engine
β”‚   β”œβ”€β”€ hunt.py                     ← PPQL parser & executor
β”‚   β”œβ”€β”€ case.py                     ← Case orchestrator
β”‚   β”œβ”€β”€ case_manager.py             ← Multi-case registry
β”‚   β”œβ”€β”€ reports.py                  ← Report exporter
β”‚   β”œβ”€β”€ research_data.py            ← Built-in reference docs
β”‚   β”œβ”€β”€ webapp.py                   ← Flask web UI (35+ routes)
β”‚   β”‚
β”‚   β”œβ”€β”€ templates/
β”‚   β”‚   β”œβ”€β”€ base.html               ← Navigation + layout
β”‚   β”‚   β”œβ”€β”€ dashboard.html
β”‚   β”‚   β”œβ”€β”€ transactions.html       ← Filterable ledger
β”‚   β”‚   β”œβ”€β”€ transaction_detail.html
β”‚   β”‚   β”œβ”€β”€ contacts.html
β”‚   β”‚   β”œβ”€β”€ social_graph.html
β”‚   β”‚   β”œβ”€β”€ chat.html
β”‚   β”‚   β”œβ”€β”€ chat_group.html
β”‚   β”‚   β”œβ”€β”€ identity.html
β”‚   β”‚   β”œβ”€β”€ analytics.html
β”‚   β”‚   β”œβ”€β”€ financial.html
β”‚   β”‚   β”œβ”€β”€ travel.html
β”‚   β”‚   β”œβ”€β”€ payment_infra.html
β”‚   β”‚   β”œβ”€β”€ audit.html
β”‚   β”‚   β”œβ”€β”€ timeline.html
β”‚   β”‚   β”œβ”€β”€ hunt.html               ← PPQL query interface
β”‚   β”‚   β”œβ”€β”€ counterparty.html       ← Per-counterparty dossier
β”‚   β”‚   β”œβ”€β”€ database_browser.html   ← Raw SQL interface
β”‚   β”‚   β”œβ”€β”€ database_sql.html
β”‚   β”‚   β”œβ”€β”€ findings.html
β”‚   β”‚   β”œβ”€β”€ research.html           ← Built-in docs index
β”‚   β”‚   β”œβ”€β”€ research_section.html
β”‚   β”‚   β”œβ”€β”€ exports.html
β”‚   β”‚   β”œβ”€β”€ cases_list.html
β”‚   β”‚   β”œβ”€β”€ case_new.html
β”‚   β”‚   β”œβ”€β”€ case_detail.html
β”‚   β”‚   └── ...
β”‚   β”‚
β”‚   └── static/
β”‚       β”œβ”€β”€ css/app.css
β”‚       └── js/app.js
β”‚
β”œβ”€β”€ .pp_forensics/                  ← Auto-created β€” case registry
β”‚   └── cases.json
β”‚
└── exports/                        ← Auto-created β€” export output
    └── <case_name>/
        β”œβ”€β”€ transactions.csv
        β”œβ”€β”€ contacts_phonepe.csv
        β”œβ”€β”€ timeline.csv
        β”œβ”€β”€ master.json
        └── report.html

🀝 Contributing

Contributions are warmly welcomed. PhonePe's app is actively developed β€” new databases and schema changes appear with each app update.

Priority Areas

  • πŸ†• New SDK parsers β€” new databases added in recent PhonePe versions
  • πŸ› Schema corrections β€” if you've found a real schema difference from your extraction
  • πŸ”Ž PPQL extensions β€” new operators, aggregations, index definitions
  • πŸ“Š Correlation heuristics β€” new suspicious signal categories
  • 🌐 Export formats β€” JSONL, XLSX, court-ready PDF templates

Development Setup

git clone https://github.com/thelocalh0st/phonepe-ios-forensics.git
cd phonepe-ios-forensics

python -m venv venv && source venv/bin/activate
pip install flask

# Run with auto-reload for development
FLASK_DEBUG=1 python run.py

Submission Guidelines

  1. Fork β†’ feature branch β†’ PR against main
  2. New parsers go in extractors.py following the existing extract_* pattern
  3. All parsers must handle None, empty tables, and partial corruption without raising exceptions
  4. Include the specific SQLite path and table/column names for any new artifact
  5. If correcting a schema error, cite the real column name and how you verified it

βš–οΈ Legal & Ethics

This tool is intended exclusively for:

  • βœ… Law enforcement β€” criminal investigations with appropriate legal authority
  • βœ… Licensed digital forensic examiners β€” working under professional mandate
  • βœ… Cybercrime investigators β€” authorized UPI fraud case analysis
  • βœ… Legal/compliance professionals β€” internal investigation with device owner consent
  • βœ… Security researchers β€” academic/responsible disclosure contexts
  • βœ… Device owners β€” analyzing your own device's data

Always ensure you have legal authorization before examining any device. Unauthorized access to a person's device data may violate the Computer Fraud and Abuse Act (CFAA), the IT Act 2000 (India), and equivalent legislation in your jurisdiction.

This tool is a read-only forensic viewer. It never writes to, modifies, or deletes any file in the evidence folder.


πŸ“š References & Further Reading

Resource Link
πŸ“ Original Research Blog Post PhonePe Forensics in iOS β€” thelocalh0st.com
πŸ“– Apple Core Data SQLite Internals Apple Developer Documentation
πŸ—ƒοΈ SQLite WAL Mode SQLite WAL Documentation
🍎 iOS App Sandbox Domains iOS Security Guide β€” Apple
πŸ’³ NPCI UPI Technical Specs NPCI β€” Unified Payments Interface
πŸ”‘ NSKeyedArchiver Format Apple plist Format Reference
πŸͺ Binary Cookie Format Satishb3 β€” Safari Binary Cookie Reader
πŸ“± iOS DFIR Fundamentals SANS FOR585 β€” Smartphone Forensic Analysis

⭐ If this tool helped your investigation, please star the repository

Every star helps more forensic examiners discover this tool.


About

PhonePe Forensics Analysis Dashboard for iOS Extractions

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors