Mimicry で TCP ポートから通信元アプリを特定してアイコン表示

背景

Mimicry の通信ログに、通信元のアプリ名やアプリアイコンを表示できるようにしました。

Mimicry の通信ログ画面

この記事では、TCP のポート番号からアプリを特定し、アイコンを取得するまでの仕組みを紹介します。

全体の流れ

  1. lsof でポート番号から PID を特定
  2. ps で PID からプロセスパスを取得し、.app バンドルを抽出
  3. .app バンドルからアイコンを取得

順番に見ていきましょう。

Step 1: ポート番号から PID を調べる

macOS の lsof コマンドを使うと、どのプロセスがどのポートを使っているかが分かります。

sudo lsof -i TCP -n -P -F pn

各オプションの意味はこんな感じです。

  • -i TCP で TCP 接続だけに絞り込み
  • -n で DNS 逆引きをスキップして高速化
  • -P でポート番号をサービス名(http など)に変換せず数値のまま出力
  • -F pn でプログラムから扱いやすい形式で出力(p が PID、n がネットワーク情報)

出力はこのようになります。

p1234
n127.0.0.1:54321->127.0.0.1:8080
p5678
n10.0.0.1:49200->93.184.216.34:443

p1234 が PID、次の行の :54321-> が送信元のポート番号です。つまり「ポート 54321 を使っているのは PID 1234」と分かります。

特定のポートに絞りたい場合はこう書きます。

sudo lsof -i TCP:54321 -n -P

Step 2: PID からアプリを特定する

PID が分かったら ps コマンドでプロセスのフルパスを取得します。

ps -p 1234 -o comm=

出力例はこんな感じです。

/Applications/Google Chrome.app/Contents/MacOS/Google Chrome

パスに .app が含まれているので、ここから /Applications/Google Chrome.app というバンドルパスが抽出できます。バンドルパスが分かればアプリ名は Google Chrome と特定できますし、アイコンも取得できるようです。

iOS Simulator 上のアプリの場合はパスに CoreSimulator が含まれるため、通常のアプリと区別できます。

/Users/xxx/Library/Developer/CoreSimulator/Devices/.../MyApp.app/MyApp

Step 3: .app バンドルからアイコンを取得する

macOS アプリの .app バンドルには Info.plist にアイコンファイル名が記載されています。

# アイコンファイル名を取得
defaults read /Applications/Safari.app/Contents/Info.plist CFBundleIconFile

ただし、返ってくるのはファイル名だけなので、実際のアイコンファイルは Contents/Resources/ ディレクトリから探す必要があります。

# Resources ディレクトリ内のアイコンファイルを確認
ls /Applications/Safari.app/Contents/Resources/AppIcon*

iOS Simulator のアプリはディレクトリ構造が異なり、.app バンドルの直下に AppIcon で始まる PNG ファイルが配置されています。

ls ~/Library/Developer/CoreSimulator/Devices/.../MyApp.app/AppIcon*

Mimicry では macOS アプリの場合は OS のサムネイル API を、Simulator アプリの場合は AppIcon*.png を直接読み込んでアイコンを表示しています。

実際に試してみる

ターミナルで一連の流れを試してみましょう。

# 1. TCP 接続の一覧を見る
sudo lsof -i TCP -n -P | head -20

# 2. 特定ポートの PID を調べる(ポート番号は適宜変更)
sudo lsof -i TCP:8080 -n -P

# 3. PID からプロセスパスを取得(PID は上で確認した値に置き換え)
ps -p <PID> -o comm=

# 4. アプリのアイコンファイルを確認
defaults read <バンドルパス>/Contents/Info.plist CFBundleIconFile

アプリ単位のフィルタリング

Mimicry ではこの仕組みを使って、通信ログをアプリ単位でフィルタリングできます。サイドバーの「アプリ」セクションにはプロキシを経由して通信したアプリがアイコン付きで一覧表示され、選択するとそのアプリの通信だけに絞り込めます。

アプリフィルタで KusumotoTodoMemo の通信だけを表示

開発中のアプリの通信だけに集中したいときに便利です。

まとめ

「ポート番号からアプリを特定してアイコンを表示する」流れは 3 ステップです。

  1. lsof でポート番号から PID を逆引き
  2. ps で PID からプロセスパスを取得し、.app バンドルを抽出
  3. .app バンドルの Info.plistAppIcon*.png からアイコンを取得

iOS Simulator 上のアプリも macOS のプロセスとして動くため、同じ仕組みで検出できます。

参考リンク