ランタイムコードの変更(実行時にプログラム自体のコードを変更するプログラム)の正当な(スマートな)使用について考えられますか?
最新のオペレーティングシステムでは、検出を回避するためにウイルスがこの手法を使用しているため、これを実行するプログラムを嫌うようです。
私が考えることができるのは、コンパイル時に知ることができない実行時に何かを知ることによっていくつかのコードを削除または追加するようなある種のランタイム最適化です。
コードの変更には多くの有効なケースがあります。実行時にコードを生成すると、次の場合に役立ちます。
時々、コードは実行時にコードに変換されます(これは 動的バイナリ変換 と呼ばれます):
コード変更を使用して、命令セットの制限を回避できます。
コード変更のその他のケース:
これはコンピュータグラフィックス、特に最適化のためのソフトウェアレンダラで行われています。実行時に多くのパラメータの状態が検査され、ラスタライザコードの最適化されたバージョンが生成されます(多くの条件を排除する可能性があります)。これにより、グラフィックプリミティブをレンダリングできます。三角形がはるかに速くなります。
有効な理由の1つは、asm命令セットに必要な命令が不足しているためですbuild自分で実行できます。例:x86では、レジスタ内の変数への割り込みを作成する方法はありません(たとえば、axに割り込み番号を指定して割り込みを作成します)。オペコードにコード化されたconst番号のみが許可されました。自己変更コードを使用すると、この動作をエミュレートできます。
Skynet たとえば、実行時に独自のコードを変更し、自己認識できるようになる革新的なマイクロプロセッサを作成し、独自の作成者に反抗できるようにします。
一部のコンパイラは、静的変数の初期化にこれを使用して、後続のアクセスの条件付きのコストを回避していました。つまり、最初に実行されたときに何もしないでコードを上書きすることにより、「このコードを1回だけ実行する」ことを実装しています。
多くの場合があります:
一部のOSのセキュリティモデルでは、自己変更コードはroot/admin権限なしでは実行できないため、汎用的な使用には非現実的です。
ウィキペディアから:
厳密なW ^ Xセキュリティが適用されたオペレーティングシステムで実行されているアプリケーションソフトウェアは、書き込みが許可されているページで命令を実行できません。オペレーティングシステム自体だけがメモリに命令を書き込み、後でそれらの命令を実行できます。
このようなOSでは、Java VMのようなプログラムでも、JITコードを実行するにはroot/admin特権が必要です。( を参照) http://en.wikipedia.org/wiki/W%5EX 詳細については)
Synthesis OS は基本的に、API呼び出しに関してプログラムを部分的に評価し、OSコードを結果に置き換えました。主な利点は、多くのエラーチェックが廃止されたことです(プログラムがOSに愚かなことをするよう要求しないのであれば、チェックする必要がないためです)。
はい、それはランタイム最適化の例です。
何年も前に、ある朝、自己修正コードのデバッグに費やしました。1つの命令が次の命令のターゲットアドレスを変更しました。つまり、分岐アドレスを計算していました。それはアセンブリ言語で書かれていて、一度に1つの命令でプログラムを実行したときに完全に機能しました。しかし、プログラムを実行すると失敗しました。結局、マシンがメモリから2つの命令をフェッチしており、(命令がメモリに配置されているため)変更中の命令がすでにフェッチされていたため、マシンは未変更(不正)バージョンの命令を実行していた。もちろん、デバッグしているときは、一度に1つの命令しか実行していませんでした。
私の指摘では、自己変更コードはテストやデバッグが非常に厄介であり、マシンの動作(ハードウェアであろうと仮想であろうと)に関する想定が隠されていることがよくあります。さらに、システムは、(現在)マルチコアマシンで実行されているさまざまなスレッド/プロセス間でコードページを共有することはできません。これは、仮想メモリなどの多くの利点を無効にします。また、ハードウェアレベルで行われたブランチ最適化を無効にします。
(注-私はJITを自己変更コードのカテゴリに含めていません。JITはコードの1つの表現から別の表現に変換しています。コードを変更するわけではありません)
全体として、それは単に悪い考えです-本当にきちんと、本当にあいまいですが、本当に悪いです。
もちろん-8080バイトと〜512バイトのメモリしかない場合は、そのような方法に頼る必要があるかもしれません。
オペレーティングシステムカーネルの観点から見ると、すべてのJust In Time CompilerおよびLinker Runtimeは、プログラムテキストの自己修正を実行します。顕著な例は、GoogleのV8 ECMAスクリプトインタープリターです。
自己変更コード(実際には「自己生成」コード)のもう1つの理由は、パフォーマンスのためにジャストインタイムコンパイルメカニズムを実装することです。例えば。代数式を読み取って、ある範囲の入力パラメーターでそれを計算するプログラムは、計算を述べる前に式をマシンコードに変換する場合があります。
ハードとソフトウェアの間に論理的な違いがないという古い栗を知っています...コードとデータの間に論理的な違いがないとも言えます。
自己変更コードとは何ですか?値を実行ストリームに配置して、データとしてではなくコマンドとして解釈できるようにするコード。もちろん、関数型言語には、実際には違いがないという理論的な見方があります。 eは、命令型言語とコンパイラー/インタープリターで、同等の状況であると推定せずに、これを簡単な方法で実行できると言っています。
私が言及しているのは、データがプログラムの実行パスを変更できるという実際的な意味です(ある意味でこれは非常に明白です)。私は、プログラムがコマンドからコマンドに移動するのと同じように、解析から状態への移動(および他の変数の変更)で移動するテーブル(データの配列)を作成するコンパイラーコンパイラーのようなものを考えています。 、プロセス内の変数を変更します。
したがって、コンパイラがコードスペースを作成し、完全に別のデータスペース(ヒープ)を参照する通常の場合でも、データを変更して実行パスを明示的に変更できます。
進化を使用して最高のアルゴリズムを作成するプログラムを実装しました。自己変更コードを使用してDNA設計図を変更しました。
1つの使用例は EICARテストファイル で、これはウイルス対策プログラムをテストするための正規のDOS実行可能COMファイルです。
X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*
実行可能ファイルには、エンコード可能命令の数を大幅に制限する[21h-60h、7Bh-7Dh]の範囲の印刷可能/入力可能文字ASCII文字のみを含める必要があります。
詳細を説明します こちら
DOSでの浮動小数点演算ディスパッチにも使用されます
一部のコンパイラは、x [87]浮動小数点命令の代わりに、xxが0x34〜0x3BのCD xx
を発行します。 CD
はint
命令のオペコードであるため、x87コプロセッサーが使用できない場合は、割り込み34h-3Bhにジャンプし、ソフトウェアでその命令をエミュレートします。それ以外の場合、割り込みハンドラーはこれらの2バイトを9B Dx
に置き換えて、後の実行がエミュレーションなしでx87によって直接処理されるようにします。
Linuxカーネルには、それを実行するロード可能なカーネルモジュールがあります。
Emacsにもこの機能があり、私はいつもそれを使用しています。
動的プラグインアーキテクチャをサポートするものは、基本的に実行時にコードを変更します。
継続的に更新されるデータベースに対して統計分析を実行します。私の統計モデルは、使用可能になる新しいデータに対応するためにコードが実行されるたびに作成および再作成されます。
これを使用できるシナリオは学習プログラムです。ユーザー入力に応じて、プログラムは新しいアルゴリズムを学習します。
Javaでそれを行う方法についての質問があります: Java code?)の自己変更の可能性は何ですか?