iPhoneバックアップデータから素で電話番号一覧などを抽出する

#PCとプログラム覚え

iPhoneが、水没にともない使えなくなりました。 私ではありません。某知り合いです。

教訓としては、iPhoneは洗濯機に入れるな、ということに尽きます。

で、お助けマンとなります。 以前のバックアップデータから、すぐに業務に必要な電話番号一覧などを抽出します。 以前といっても半年前データでしたが、ないとあるとでは大違い。

sqlite3とシェルスクリプトを走らせることができれば、OS環境は問わないと思います(多分)。

iPhoneのバックアップデータは、macOSの場合は

/Users/ユーザ名/Library/Application Support/MobileSync/Backup/

にあります。

ハッシュ値で、バックアップ時点ごとのパスができてます。

/Users/ユーザ名/Library/Application Support/MobileSync/Backup/10663fbacfbe以下略

みたいな感じ。

/Users/ユーザ名/Library/Application Support/MobileSync/Backup/10663fbacfbe以下略/Info.plist

に、基本情報がはいってます。

<key>Device Name</key>
        <string>iPhone-X-MY-device-2</string>

とかみれば、どのiPhoneのいつのbackupかはわかります。

事故を増幅させないように、うえのbackupをそのまま使わず、 /tmp/なりなんなりに、コピーして、試してください。

同じパス階層に、Manifest.dbってのがあって、こいつが、メインのdbです。(sqlite3の)。

ただし、欲しい<情報>に対応して、それぞれデータベースが乱立しています。

とにかく本人が確保したいのは、3つで

  • 電話番号
  • ショートメッセージ
  • LINEチャット

です。

次のようスクリプトを書きます。 /tmp/Backup/などで、走らせます。

#!/bin/bash
# バックアップID
BACKUP_ID="上のハッシュ値のパス" # 10663fbacfbe以下略の部分

# 1. 各データベースのパス(LINEはManifest.dbからファイル名を取得)
#これは任意のハッシュ値にみえながら、実は、電話番号、smsの一意のデータベース名

PHONE_DB="$BACKUP_ID/31/31bb7ba8914766d4ba40d6dfb6113c8b614be442"
SMS_DB="$BACKUP_ID/3d/3d0d7e5fb2ce288813306e4d4636395e047a3d28"

LINE_HASH=$(sqlite3 "$BACKUP_ID/Manifest.db" "SELECT fileID FROM Files WHERE relativePath LIKE '%Line.sqlite' LIMIT 1;")
LINE_DB="$BACKUP_ID/${LINE_HASH:0:2}/$LINE_HASH"


# 2. 3つ並べて実行
sqlite3 "$PHONE_DB" ".read phone.sql" > /tmp/phone.txt
sqlite3 "$SMS_DB" ".read sms.sql" > /tmp/sms.txt
sqlite3 "$LINE_DB" ".read line.sql" > /tmp/line.txt

同じディレクトリにおく3つのsqlですが

それぞれのsqlは

phone.sql

SELECT 
    p.Last AS "姓", 
    p.First AS "名", 
    m.value AS "電話番号"
FROM 
    ABMultiValue m
JOIN 
    ABPerson p ON m.record_id = p.ROWID
WHERE 
    m.property = 3;

sms.sql

SELECT 
    datetime(m.date / 1000000000 + 978307200, 'unixepoch', 'localtime') AS "日時",
    h.id AS "相手の宛先(電話番号/ID)",
    m.is_from_me AS "自分が送信(1=はい, 0=いいえ)",
    m.text AS "メッセージ本文"
FROM 
    message m
LEFT JOIN 
    handle h ON m.handle_id = h.ROWID
ORDER BY 
    m.date DESC;

line.sql

SELECT 
    datetime(m.ZTIMESTAMP / 1000, 'unixepoch', 'localtime') AS "日時",
    COALESCE(g.ZNAME, u_chat.ZNAME, '個人トーク') AS "トークルーム名",
    CASE 
        WHEN m.ZSENDER IS NULL THEN '自分'
        ELSE u_sender.ZNAME 
    END AS "発言者",
    m.ZTEXT AS "メッセージ本文"
FROM 
    ZMESSAGE m
-- チャットルームの紐付け
LEFT JOIN 
    ZCHAT c ON m.ZCHAT = c.Z_PK
-- グループチャットの場合のルーム名取得
LEFT JOIN 
    ZGROUP g ON c.ZMID = g.ZID
-- 1対1チャットの場合の相手のユーザー名取得
LEFT JOIN 
    ZUSER u_chat ON c.ZMID = u_chat.ZMID
-- メッセージ発言者の名前取得(NULLなら自分)
LEFT JOIN 
    ZUSER u_sender ON m.ZSENDER = u_sender.Z_PK
WHERE 
    m.ZTEXT IS NOT NULL
ORDER BY 
    m.ZTIMESTAMP DESC;

ご覧のようにLINEは他社の情報なので、Manifest.dbから、Lineのsqliteデータベース名を取得したうえで、動作させます。

ともかく、これで必要最小限のデータは確保できました。 (LINE画面でバックアップ設定をしてないと、携帯をかえるだけで過去履歴が消えて終わる^^;、という伝説があるLINEチャットも、単なるテキストですけど、取得可能なのは、便利でしょw)

Popup