ようやくここまでたどり着きました。以前 elfバイナリでやったことのMach-O版です。
実行体は外部.soの何かの関数を呼び出しているとして、その関数への参照をフックしたいという要求に応えてみたいと思います。
フックした後の関数は実行体内部に存在するとします。
これらの関係を図示すると以下のようになります(図は以前の使い回しです…)。
今までに調査してわかっている内容を利用するとこれが実現出来ます。
前提条件にあるように外部の共有ライブラリを利用する場合、インポート関数テーブルが生成されます。このテーブルが参照するデータの中に関数の実体が格納される部分がありました。このあたりの調査過程はこちらの記事を参考にしてみてください。
この la_symbol_ptrセクションの該当する部分を求めて、置き換えたい関数のアドレスに更新するだけで処理は完了です。
実は、jump_tableだとか __IMPORTというセクションも存在するらしいのですが、手元ではこれらの実行体を作ることが出来ず未確認です。
準備
ロードコマンド LC_SYMTAB からシンボルテーブルの位置を求める
ロードコマンド LC_STRTAB からストリングテーブルの位置を求める
ロードコマンド LC_DYSYMTAB から動的シンボルテーブルの情報を取得する
セクションの情報を処理して、la_symbol_ptrのセクション情報を取得する
フック仕込み
関数名から関数のアドレスが書かれている場所を求めるまでは以下のようになります。
シンボルテーブルの中身(nlist構造体の配列)の中から関数名情報を求める。
関数名がフックを仕込みたい関数名かどうかをチェック。
次にその関数が Indirectテーブルの中でどの位置にあるかを検索
上記で求まった序数で、インポートテーブルの場所を特定し、その中に新しい関数のアドレスを書き込んでおく。
ここでのポイントは序数はあくまでインポートテーブルでの序数とするため、reserved1で示される開始インデックス値を引いて求める必要があります。
インダイレクトテーブルに関しては以前の記事にて走査の方法が使えるのでここでは割愛します。