Mac / iOS 開発担当の松本です。
皆さんご存知のように iOS アプリを作るのに欠かせない Objective-C は、メソッドの解決が動的なこともあり、C言語のファミリーでありながら強力なリフレクション機能を備えています。そのリフレクションの必要性等から、実行ファイルには様々な情報が埋め込まれていて、何気なくバイナリエディタで開いただけで、テンションが上がるバイナリに仕上がっています。のぞかずにはいられませんね。という訳で今日はこのバイナリを少しのぞいてみたいと思います。
まずはバイナリの概要を抑えておきましょう。iOS 上の実行ファイルは Mach-O という形式で(まーく・おーと読むらしい)、これは Windows や Linux でいうところの EXE や ELF にあたります。この Mach-O のフォーマットについては
アップルからドキュメントが提供されていますね。
細かい話はドキュメントをみて頂くとして、Mach-O オブジェクトは大きくは3つの部分に分けられます。
- ヘッダ
- ロードコマンド
- データ
このうちロードコマンドの中のテキストセグメント内に、クラス名一覧やらメソッド名一覧やらが含まれています。なのでとりあえず読みたいのはロードコマンド周辺だという事です。
さて早速バイナリをのぞいていきたい訳ですが、ドキュメントと16進数を交互に眺めながらというのはしんどいです。幸いな事に MachOView という簡単便利なフリーな GUI ツールがあります。おもむろに実行ファイルを開いてみましょう。試しに Sleipnir Mobile のバイナリを開いてみると以下のようになります。
なんとクラス名も、メソッド名も、使用しているフレームワークも丸見えです。怖いですね。恥ずかしい名前付けられないですね。恥ずかしい設計できないですね。このように大まかにですがバイナリデータから、どのようにそのアプリが実現されているのかを読み取る事ができます。是非一度自分で作ったアプリを覗いてみて下さいね。
さて GUI ツールは何となく全体を見たりするには便利なんですが、欲しい情報が解っている場合などは煩わしいですね。そこで欲しい情報によって、幾つかコマンドラインツールを使い分けましょう。
$ otool -vh [file] | Mach-O ファイルのヘッダを出力します。 |
$ otool -vL [file] | リンクされているライブラリ一覧を出力します。 |
$ otool -vl [file] | Mach-O ファイルに含まれるロードコマンド一覧を取得します。含まれるセグメントの確認に使用します。 |
$ otool -v -s [segname] [secname] [file] | 指定したセグメントとセクションの情報を出力します。 |
$ nm [file] | シンボルテーブル一覧を出力します。 |
$ strings [file] | オブジェクトファイルに含まれる文字列の一覧を出力します。 |
$ class-dump [file] | Cocoa プログラマお馴染み。バイナリからヘッダファイルを吐きます。 |
如何でしょうか。機械しか読めないはずのバイナリから思ったよりもたくさんの情報が得られると感じたのではないでしょうか。残念ながら App Store から購入したアプリのバイナリは、一部が暗号化されていて一筋縄では読み出す事ができませんが、サンプルアプリや同様の実行ファイル形式である Mac アプリからは簡単に情報を読み取る事ができます。
自分が書いたコードがどのようにコンパイルされているのか、たまにはそんな事に思いを馳せるのも楽しいですね。