happy-app-audit について
Happy App Auditは、インストール済みmacOSアプリのテレメトリーを静的に調べるスキルです。メタデータ、文字列、SDK指紋、エンドポイント、ローカルデータを分析し、読み取り専用とプライバシー保護の規則に沿ってMarkdownレポートを作成します。
主な機能
- 01macOSアプリバンドルの静的検査
- 02サードパーティSDK指紋の照合
- 03エンドポイントと用途の整理
- 04ローカルデータパスの一覧化
- 05Markdown監査レポートの生成
- 06読み取り専用分析とデータ伏字
活用シーン
- 01インストール済みアプリのテレメトリー確認
- 02アプリが参照するエンドポイントの整理
- 03アプリ関連のローカルファイルの確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ iamzhihuix/ happy-claude-skills --skill happy-app-auditインストール後、Claude Code で/happy-app-auditを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
lib/card.tsshell.tsreferences/data_locations.mdknown_endpoints.mdmethodology_examples.mdsafe_commands.mdsdk_fingerprints.mdscripts/classify_strings.tsinventory_data.tsmatch_fingerprints.tsrender_report.tsrun.tssnapshot_app.tstemplates/card_prompt.md.tmplreport.md.tmpl詳細
Happy App Audit
静的解析のみでmacOSアプリのテレメトリーを監査します。インストールされた.appバンドルが何を、誰に、どのくらいの頻度で(推定)、報告しているか、またディスク上に何を残すかを記述したMarkdownレポートを生成します。
呼び出すタイミング
ユーザーが.appのパスまたはアプリ名とともに、「审计 / 调查 / 看看 / 拆 / 逆向 / 上报 / 埋点 / 隐私 / 抓 SDK」のいずれかを指定した場合に呼び出します。また、/Applications、~/Applications、/Library/Input Methods、/Library/PrivilegedHelperTools配下のパスが指定された場合も呼び出します。
次の場合は呼び出さないでください。ソースコードリポジトリ、Webサイト、モバイル(iOS/Android)パッケージ。このスキルはmacOSバンドル専用です。
厳守事項(交渉不可)
- 読み取り専用です。 発見したエンドポイントに対する
curl/wget/nc/digは禁止です。lldb attach、dtrace、fs_usage、tcpdump、mitmproxy、fridaも禁止です。Keychainの読み取り、DRMの回避、メモリダンプも禁止です。 - 許可されたコマンドのみ使用します。
references/safe_commands.mdを参照してください。許可リストにないコマンドが必要と思われる手順がある場合は、独自に対応せず、停止してユーザーに伝えてください。 - プライバシーをデフォルトで保護します。 すべての出力ファイルで、
device_id、uid、session_id、email、IDFV、IDFA、JWT、および16桁以上の16進数の文字列を<redacted:N>に置き換えてください(長さは維持し、内容は削除します)。 - 対象範囲の上限。 1回の呼び出しで5個を超えるアプリを対象とする場合は拒否してください。
/System/、/usr/libexec/、/private/var/db/com.apple.*配下のパスは拒否してください。これらはOSコンポーネントであり、サードパーティのテレメトリー監査対象ではありません。
ランタイム
{baseDir} = このSKILL.mdがあるディレクトリです。
すべてのスクリプトはbun + TypeScriptです。ランタイムは次のように解決します。PATH上にbunがあれば優先して使用し、なければnpx -y bunを使用します。どちらもない場合は、インストール方法を1行で案内して中止してください。
# Smoke check
bun --version || npx --version || echo "Need bun (recommended) or npx"
ワークフロー — 順番どおりの6フェーズ
各フェーズには、目的 → 入力 → コマンド → 出力 → 停止条件があります。先に進んだり、順序を入れ替えたりしないでください。
Phase 0 — 対象範囲の確認
目的。 対象リストを、有効な.appパス5個以下に確定します。
入力。 ユーザーが伝えた内容です。パス、名前、または「インストール済みの入力メソッド」などが該当します。
コマンド。
- ユーザーがパスを指定した場合 → 存在し、
.appで終わることを確認します - ユーザーが名前を指定した場合 → 固定リストを検索します:
/Applications (depth 2) ~/Applications (depth 2) /Library/Input Methods (depth 1) /Library/PrivilegedHelperTools (depth 1) /System/、/usr/libexec/、/private/var/db/com.apple.*配下のものは拒否します
出力。 絶対パスを格納したtarget_apps[]のリストです。
停止条件。 リストが空の場合は、ユーザーに一度だけ確認します。5個を超える場合は、どれを残すか尋ねます。
Phase 1 — メタデータのスナップショット
目的。 アプリごとに変更されない情報、つまりバンドルID、バージョン、署名、エンタイトルメント、ネットワークポリシー、埋め込みフレームワークを取得します。
入力。 Phase 0のtarget_apps[]です。
コマンド。 scripts/snapshot_app.tsを実行します:
bun {baseDir}/scripts/snapshot_app.ts <app-path> --out <workdir>/meta.json
スクリプトは以下を収集します:
plutil -p <app>/Contents/Info.plistcodesign -dv --entitlements - <app>(標準エラー)find <app>/Contents/Frameworks -maxdepth 3 -name '*.dylib' -o -name '*.framework'otool -L <main-binary>- アーキテクチャを確認するための
file <main-binary> du -shによるサイズ
出力。 <workdir>/meta.json。以下を含みます:bundle_id、version、sandboxed、arbitrary_loads、ats_exceptions[]、entitlements_summary[]、frameworks[](各項目:name、path、size_bytes、archs)。
停止条件。 bundle_idを読み取れない場合は中止します。アプリの形式が不正です。
フェーズ 2 — 文字列の前処理
目標。 埋め込まれたすべてのバイナリから生の strings を取得し、コンテキストに収まるよう分類した Markdown に変換します。
入力。 meta.json::frameworks[]。
コマンド。
bun {baseDir}/scripts/classify_strings.ts <workdir>/meta.json --out <workdir>/strings/
各バイナリについて、スクリプトは strings -a -n 6 を実行し、各行を次のいずれかに分類します。
urls—https?://に一致するものdomains— ホスト名のみのものpaths—/Library/...、~/Library/...、コンテナ相対パスsql—CREATE TABLE、INSERT INTO、SELECT ... FROMevents— イベント名らしきもの(/^[a-z][a-z0-9_]{8,80}$/に一致し、アンダースコアを少なくとも 1 つ含むもの)keys— 24 文字以上の base64/16 進数の文字列(件数と先頭 12 文字のみを保持し、全文は保持しない)noise— 破棄
出力。 <workdir>/strings/<binary-name>.{urls,domains,paths,sql,events}.md(keys バケットには件数と一部を伏せたプレビューのみを格納します)。
停止条件。 バイナリが 200 MB を超える場合はスキップし、警告行を出力します。OOM を起こさないでください。
フェーズ 3 — SDK フィンガープリントの照合
目標。 存在するサードパーティ SDK と、その確信度を特定します。
入力。 <workdir>/strings/、および references/sdk_fingerprints.md。
コマンド。
bun {baseDir}/scripts/match_fingerprints.ts <workdir>/strings/ \
--fingerprints {baseDir}/references/sdk_fingerprints.md \
--out <workdir>/matched.md
スクリプトは、各フィンガープリントの tell-tale strings 正規表現セットを分類済みの文字列に適用します。フィンガープリントごとに定義された min_hits のしきい値に達した場合、そのフィンガープリントは確認済みとみなされます。
出力。 <workdir>/matched.md に SDK ごとに 1 行を出力します。各行には、名前、ベンダー、ヒット数、証拠となるファイルの行、ステータス(確認済み/一部一致/不在)を記載します。
停止条件。 確認済みのフィンガープリントが 0 件で、アプリにサードパーティの .framework も埋め込まれていない場合は、「テレメトリーは検出されませんでした」という 1 行のレポートを作成し、フェーズ 4〜5 をスキップします。
フェーズ 4 — エンドポイントのマッピング
目標。 「どこに、どのプロトコルで、何の目的で、どのくらいの頻度で通信しているか」に答える表を作成します。
入力。 <workdir>/strings/*.urls.md + <workdir>/strings/*.domains.md + <workdir>/matched.md + references/known_endpoints.md。
コマンド。 このフェーズでは、Claude がファイルを読み取る作業が中心です。機械的に行う手順は次のとおりです。
bun {baseDir}/scripts/match_fingerprints.ts <workdir>/strings/ \
--fingerprints {baseDir}/references/known_endpoints.md \
--out <workdir>/endpoints.md
次に Claude が <workdir>/endpoint_table.md を作成します。
| エンドポイント | SDK | プロトコル | 推定される目的 | 頻度の情報源 |
|---|
頻度の情報源 には、<workdir>/strings/ で見つかった具体的な間隔、フェーズ 5 で見つかった設定ファイル、または「不明 — 静的な証拠には記載なし」のいずれかを必ず記載します。決して推測しないでください。
停止条件。 endpoints.md が空でもフェーズ 3 で SDK が確認されている場合は、レポートに記載します(実行時にホストが解決されている可能性があります)。
フェーズ 5 — ローカルデータの調査
目標。 アプリがディスク上に書き込むデータを網羅的に調査します。
入力。 meta.json::bundle_id、および references/data_locations.md。
コマンド。
bun {baseDir}/scripts/inventory_data.ts <bundle_id> --out <workdir>/local_data.md
スクリプトは次の場所を find します。
~/Library/Application Support/<bundle>/~/Library/Containers/<bundle>/Data/~/Library/Group Containers/group.<bundle-prefix>.*/~/Library/Caches/<bundle>/~/Library/Preferences/<bundle>.plist~/Library/Logs/<bundle>/
各 .sqlite* ファイルに対して、sqlite3 <file> '.schema' と .tables のみを実行します。SELECT は決して実行しません。各 .mmkv/.json 設定ファイルについては、パスとサイズを列挙し、開かないでください。
出力。 <workdir>/local_data.md に、該当するパスのツリー、サイズ、SQLite スキーマを記載します。
停止条件。 ユーザーがファイルの所有者でない場合は、メモを添えてスキップします(sudo を促さないでください)。
フェーズ 6 — レポートのレンダリング(+任意の 4:5 カード)
目標。 ユーザー向けレポートを組み立てます。共有用に 4:5 のインフォグラフィックカードを任意でレンダリングします。
入力。 これまでのすべてのフェーズの出力。
コマンド。
bun {baseDir}/scripts/render_report.ts <workdir> \
--template {baseDir}/templates/report.md.tmpl \
--out ~/Documents/app-telemetry-audit/<YYYY-MM-DD>_<bundle-id>/report.md
scripts/run.ts に --card を渡すと、オーケストレーターはさらに次の処理を行います。
lib/card.ts::renderCardPrompt()を呼び出します。この関数は、上位 6 件の SDK(サイズ順。プライバシー上注意が必要なものは赤で表示)、上位 6 件のエンドポイント(endpoints.mdで確認済みの一致を優先し、中国語の用途ラベルを付け、quic/-ws.ホストのプロトコルを合成)、および上位 5 件のローカルデータの分類(親ディレクトリと注記でまとめ、DoubaoIme/doubaoimeの大文字・小文字の表記違いを統合)を抽出します。- 入力済みのプロンプトを
<workdir>/card_prompt.mdに書き込みます。 ~/.claude/skills/baoyu-imagine/scripts/main.ts(またはBAOYU_IMAGINE_SCRIPT環境変数)からbaoyu-imagineを自動検出し、デフォルトの--ar 4:5 --quality 2kを指定して呼び出し、<workdir>/card.pngに書き込みます。
--no-image を渡すと、プロンプトのみを書き込み、画像の生成をスキップします。--image-provider、--image-model、--image-imageSize など、任意の --image-* フラグを渡すとデフォルトを上書きできます。たとえば、ネイティブの nano-banana-pro による 4K 出力には --image-provider google --image-model gemini-3-pro-image-preview --image-imageSize 4K を指定します。
baoyu-imagine がインストールされていない場合でも、フェーズ 6 は card_prompt.md を書き込み、インストール方法を案内しますが、PNG の生成はスキップします。このスキルは、インストールされていなくても完全に機能します。
出力。 最終的な Markdown レポート。その絶対パスを出力します。--card を指定した場合は、card_prompt.md と card.png も出力します。
出力レイアウト(アプリごと)
~/Documents/app-telemetry-audit/<YYYY-MM-DD>_<bundle-id>/
├── meta.json
├── matched.md
├── endpoints.md
├── endpoint_table.md
├── local_data.md
├── strings/
│ └── <binary>.{urls,domains,paths,sql,events}.md
├── card_prompt.md # only if --card requested
└── report.md # the deliverable
作業ファイル(strings/、中間生成された *.md)はデフォルトで保持されます。これらは監査証跡です。report.md の書き込み後に削除するには、--clean を渡します。
クイックスタート
# Single app, full audit (markdown report only)
bun {baseDir}/scripts/run.ts /Library/Input\ Methods/DoubaoIme.app
# Add a 4:5 share card (prompt + PNG via baoyu-imagine)
bun {baseDir}/scripts/run.ts /Library/Input\ Methods/DoubaoIme.app --card
# Card prompt only — skip image generation
bun {baseDir}/scripts/run.ts /Library/Input\ Methods/DoubaoIme.app --card --no-image
# Card with Google nano-banana-pro at 4K
bun {baseDir}/scripts/run.ts /Library/Input\ Methods/DoubaoIme.app --card \
--image-provider google \
--image-model gemini-3-pro-image-preview \
--image-imageSize 4K
# Multiple apps in one go (capped at 5)
bun {baseDir}/scripts/run.ts /Library/Input\ Methods/DoubaoIme.app /Applications/Foo.app
scripts/run.ts はフェーズ 1~6 を順に呼び出す薄いオーケストレーターです。一般的なケースではこちらを使用してください。個々のフェーズ用スクリプトは、反復作業を行う場合にのみ使用してください。
--card フラグ一覧
| フラグ | 用途 | デフォルト |
|---|---|---|
--card | card_prompt.md と card.png をレンダリング | オフ |
--no-image | --card と併用:プロンプトを書き込み、PNG の生成をスキップ | オフ |
--image-provider | baoyu-imagine のプロバイダー(google、openai、replicate、dashscope、…) | プロバイダーを自動選択 |
--image-model | プロバイダー内のモデル ID | プロバイダーのデフォルト |
--image-ar | アスペクト比 | 4:5 |
--image-size | 明示的な WxH | --image-quality/プロバイダーの設定に基づく |
--image-quality | normal または 2k | 2k |
--image-imageSize | Google/OpenRouter の 1K/2K/4K | --image-quality に基づく |
--out | 出力ルートを上書き | ~/Documents/app-telemetry-audit/ |
--image-* フラグを指定すると、--card も自動的に有効になります。
関連資料
references/safe_commands.md— コマンドの許可リストと根拠references/sdk_fingerprints.md— SDK の検出ルール(MVP で 12 種以上の SDK に対応)references/known_endpoints.md— ドメインから製品を逆引きする一覧references/data_locations.md— ベンダーごとの一般的なディスク上の配置references/methodology_examples.md— 手順の実例 2 件(WeType、DoubaoIme)templates/report.md.tmpl— 最終レポートのひな形templates/card_prompt.md.tmpl— 4:5 ビジュアルカードのプロンプトひな形
Claude がしてはいけないこと
- リテラルの根拠となる行とファイルパスを引用せずに、文字列を「X のように見える」と言い換えないでください。
- SDK 名から頻度を推測しないでください。頻度は、文字列または設定ファイルにあるリテラルの数値からのみ判断してください。
- 対象アプリ内のバイナリを実行しないでください。
.sqliteの内容を開かないでください。スキーマのみを確認してください。- フェーズ 3 で何も見つからなかった場合は、レポートを書かずに、代わりに短い「テレメトリーは検出されませんでした」という注記を書いてください。
- 学習時の記憶からエンドポイントを捏造しないでください。URL が
<workdir>/strings/にない場合、表に含めないでください。
検証(このスキルの開発時)
/Library/Input Methods/DoubaoIme.app でスモークテストを実施し、レポートに次の内容が含まれていることを確認してください。
- フレームワーク:
applogrs、Parfait、bytenn、onnxruntime、sscronet、TTNet、ime_net_sdk、sami - エンドポイント:
ime.doubao.com/obric/ime/cloud/convert、log-klink.zijieapi.com、ime-gw.oceancloudapi.com、frontier-audioのうち、少なくとも 3 つ - ローカルデータ:
~/Library/Application Support/DoubaoIme/Parfait/ready/685343/0/
回帰テスト:WeType IME バンドルで実行し、wetype.weixin.qq.com と CACHE_LOG_TBL スキーマが表示されることを確認してください。
ネガティブテスト:サードパーティ製のテレメトリを含まない小規模なアプリで実行し、SDK をでっち上げることなく、「テレメトリは検出されませんでした」という短い出力が生成される必要があります。