mmap()
まず、観察:マシン命令をメモリに入れたり、ファイルに保存したりする必要があるということは何もありません。read()
これもwrite()
可能ですが、この目的のために書き込み可能で実行可能なプライベートマッピングを作成する必要があることに注意してください。
同じプロセス内で実行される場合、スタックが使用できなくなるため、ロードする実行可能コードへの呼び出しを行うスタックの領域への書き込みを確実に無効にすることはできません。これを回避するには、変数にアノテーションを付けるか、アセンブリを使用します。
次のオプションはfork()
です。子を特別なラッパー実行可能exec
ファイルに入れて、悪意のある実行可能コードによる損傷と内省を最小限に抑えることができます(単にロード/ダンプを提供します)。または、子に同じ効果をもたらすように変更させることで同じことを行うことができます。これはまだ100%安全ではありません。
提案0
- 最小限のライブラリに対してリンクされているスタンドアロンのバイナリを作成します(
-nodefaultlibs
)。
- の後に
fork
、ptrace(PTRACE_TRACEME)
子で(メモリの内容を確実に読み取り、他の介入を実行できるように)、パイプ以外のすべてのハンドルを閉じます(stdin
簡単にするために)。exec()
前述のラッパーバイナリに。
ラッパーバイナリの場合:
mmap
書き込みおよび実行権限を持つ既知の場所のプライベートリージョン。または、サイズが固定されている場合は、この領域を静的に割り当てることができます。
- パイプの内容をリージョンに読み込みます。
- パイプを閉じます。現在、プロセスには開いているハンドルがありません。
prctl(PR_SET_SECCOMP, 1)
。現在、有効なシステムコールは_exit
とだけですsigreturn
。プロセスはできないので、raise
有用sigreturn
な効果はないはずです。
- メインスタックから書き込み権限を削除します(唯一のスタックである必要があります)。戻るつもりはなく、すぐにジャンプするので、スタックに再度触れる必要はありません。
- リージョン内の開始位置にジャンプします。アセンブリを使用してこれを行うか、関数ポインターを作成して呼び出します(スタックにプッシュせずに機能させることができる場合)。これで、使用可能な唯一の書き込み可能な領域であるメモリ領域を実行する必要があります。メインスタックは保護されており、ライブラリがサポートされていないため、ヒープを使用しないでください。
親の場合:
ptrace
またはを使用しwait
て、誤った完了または正常な完了をキャッチします。
/proc/<pid>/mem
ファイルを介して、またはファイルと同等の既知の場所にあるマップされた領域を読み取ります。