これはエレガントではないので、より良いアイデアに興味がありますが、基本的に機能させることができたものの要約を次に示します。
これは、元の elf のパディングに挿入された小さなブートストラップ ペイロードの 2 つのアプローチであり、mmap() は、実際の作業を行うために、任意に大きなバイナリ BLOB を挿入します。
パート I: ブートストラップ ペイロード
基本的に、.ARM.exidx セクション (コード セグメントの先頭にロードされる) と .preinit_array セクションの間のパディングに少量のコードを挿入します。このコードは、別のバイナリ BLOB を開き、mmap() で読み取り専用として実行し、ハード コーディングされた仮想アドレスで安全であることを願っています。
挿入したコードをメインの実行可能ファイルの一部としてロードするには、elf ファイルのロード セグメントのサイズを変更する必要がありました。この場合は、0x54 から始まる 2 番目の phdr 構造体です。0x64 (0x54+0x20) の p_filesz と 0x68 (0x54+0x24) の p_memsz の両方が変更されました。
また、オフセット 0x18 にある elf ヘッダーの e_entry 開始アドレスを、挿入したコードを指すように変更しました。挿入されたコードは、セットアップが完了すると古い開始アドレスにジャンプします (実際には、最初に大きなペイロードのステージ 2 セットアップにジャンプし、次に元のアドレスにジャンプします)。
最後に、トラップしたい関数の静的にリンクされた syscall スタブを変更して、mmap() しているより大きなペイロードのロード アドレスにある置換を指すようにしました。
パート II: 大きなペイロード
これは、行われている変更を実装します。私の場合、システムコールを、特定の条件が満たされたときにログに記録する関数に置き換えます。メインの実行可能ファイルは静的にリンクされているため、これも静的にリンクする必要があります。もっと簡単に言えば、C ライブラリを使用できません。代わりに、アセンブリ言語を使用して、基本的な I/O のシステムコールを発行します。実行可能ファイルとして読み込まれないと、永続的なローカル変数ストレージがないことに気付きました。そのため、起動時に、ローカル変数を保持する匿名ページを mmap() します。ほとんどの場合、ログに記録しているファイルの fd と、デバイス ドライバー fd の操作です。ログに記録する必要があります。
この部分のコンパイルは少し洗練されていません。-S スイッチを gcc に指定してアセンブリにコンパイルし、すべてのセクション キーワードを削除しています。次に、それを gcc に渡し、オブジェクトをアセンブルして生成します。最初の関数の名前をエントリ ポイント (-e) として指定し、0x8000 開始オフセットを削除する通常のリンカー スクリプトのカスタマイズを使用して、リンカーを介してこれを実行します。ただし、ヘッダーによるオフセットがまだあります。この場合は 128 バイトです。フィックスアップを保持するために、リンクされた elf の内容をバイナリ BLOB に objcopy し、/dev/zero から 128 バイトを自分で dd し、それを先頭に挿入します....
私が言ったように...これはエレガントではないので、私はより良いアイデアを受け入れます