自己変更コードの実際の用途はありますか?
ワーム/ウイルスの作成に使用できることは知っていますが、プログラマーが自己修正コードを使用しなければならない正当な理由があるのではないかと考えていました。
何か案は?架空の状況も歓迎します。
" 自己変更コード "のウィキペディアのエントリには素晴らしいリストがあることがわかりました。
- 半自動最適化状態依存ループの。
- ランタイムコード生成、またはキー比較を実行するためのコードを準備する一般的なソートユーティリティなど、ランタイムまたはロードタイムでのアルゴリズムの特殊化(たとえば、リアルタイムグラフィックスのドメインで人気があります)特定の呼び出しで説明されています。
- インライン化された状態の変更オブジェクトの、またはクロージャの高レベルの構築をシミュレートします。
- サブルーチンアドレス呼び出しのパッチ、通常はダイナミックライブラリのロード時に行われるか、呼び出しごとに、実際のアドレスを使用するようにサブルーチンの内部参照をパラメータにパッチします。これが「自己修正コード」と見なされるかどうかは、用語の場合です。
- 進化的計算システム遺伝的プログラミングなど。
- 逆アセンブラまたはデバッガを使用する場合のように、コードを非表示にしてリバースエンジニアリングを防止。
- ウイルス/スパイウェアスキャンソフトウェアなどによる検出回避へのコードの隠蔽。
- (一部のアーキテクチャでは)メモリの100%を、繰り返しオペコードのローリングパターンで埋めて、すべてのプログラムとデータを消去、またはバーンインハードウェアにします。
- コードの圧縮実行時に解凍して実行します。たとえば、メモリやディスクの容量が限られている場合などです。
- 非常に限られた命令セットの中には、自己修正コードを使用して特定の機能を実現する以外に選択肢がないものがあります。たとえば、負の場合の減算と分岐の「命令」のみを使用する「One Instruction Set Computer」マシンは、間接コピーを実行できません(Cプログラミングの「* a = ** b」に相当するものなど)。言語)自己修正コードを使用せずに。
- フォールトトレランスの手順を変更する
自己修正コードを使用してハッカーを阻止することについてのポイント:
いくつかのファームウェアアップデートの過程で、DirectTVはスマートカード上にプログラムをゆっくりと組み立て、ハッキングされて未払いのチャネルを違法に受信したカードを破壊しました。詳細については、 Black Sunday Hack に関するJeffのCodingHorrorの記事を参照してください。
私は次の目的で使用される自己修正コードを見てきました:
プログラムにその場でより多くのコードを記述させることによる速度の最適化
難読化、リバースエンジニアリングをはるかに困難にする
RAMが制限されていた以前は、自己修正コードを使用してメモリを節約していました。最近では、たとえば [〜#〜] upx [〜#〜] などのアプリケーション圧縮ユーティリティを使用しています。 =アプリケーションの圧縮イメージをロードした後、独自のコードを解凍/変更するために使用されます。
コモドール64には多くのレジスタがなく、1Mhzプロセッサを搭載しているためです。値によってオフセットされたメモリアドレスを読み取る必要がある場合は、ソースを変更する方が簡単です。
@Reader:
LDA $C000
STA $D020
INC Reader+1
JMP Reader
とにかく自己修正コードを書いたのはこれが最後です:-)
それは本当に本当にクールだからです、そして時々それは十分な理由です。
1960年代のアセンブリ言語は、自己修正コードを使用して、スタックなしで関数呼び出しを実装していました。
クヌース、v1、1ed p.182:
_MAX100 STJ EXIT ;Subroutine linkage
ENT3 100 ;M1. Initialize
JMP 2F
1H CMPA X,3 ;M3. Compare
JGE *+3
2H ENT2 0,3 ;M4. Change m
LDA X,3 ;(New maximum found)
DEC3 1 ;M5. Decrease k
J3P 1B ;M2. All tested?
EXIT JMP * ;Return to main program
_
このコーディングをサブルーチンとして含むより大きなプログラムでは、単一の命令「JMP MAX100」により、レジスタAが位置X +1からX + 100の現在の最大値に設定され、最大値の位置がrI2に表示されます。 。この場合のサブルーチンリンケージは、「MAX100 STJ EXIT」、後で「EXITJMP *」の命令によって実現されます。 Jレジスタの動作方法により、終了命令は、MAX100への最初の参照が行われた場所の次の場所にジャンプします。
編集:ここで簡単に説明しても、何が起こっているのかを理解するのは難しいかもしれません。行_MAX100 STJ EXIT
_で、_MAX100
_は命令(したがってプロシージャ全体)のラベルです。STJ
はジャンプレジスタをSTOREすることを意味します(ここでfrom )、EXIT
は、「EXIT」というラベルの付いたメモリ位置がSTOREのターゲットであることを意味します。 EXIT
、後で見るのは最後の命令のラベルです。つまり、コードを上書きしています!ただし、多くの命令(ここではSTJ
を含む)は、命令Wordのオペランド部分のみを暗黙的に上書きします。したがって、JMP
は変更されないままであり、_*
_はダミートークンです。そこに置く意味のあるものは実際には何もないため、上書きされるだけです。
自己変更コードは、レジスタ間接アドレス指定が利用できない場合にも使用されますが、必要なアドレスはレジスタのすぐそこにあります。 PDP-1 LISP:
_dap .+1 ;deposit address part of accumulator in (IP+1)
lac xy ;load accumulator with (ADDRESS) [xy is a dummy symbol, just like * above]
_
これらの2つの命令は、ロード命令のオペランドを変更することによってACC := (ACC)
を実行します。
このような変更は比較的安全であり、アンティークのアーキテクチャでは必要です。
人工知能?
多くの理由があります。頭のてっぺんから:
ランタイムクラスの構築とメタプログラミング。たとえば、SQLテーブルへの接続を取得し、そのテーブルに特化したクライアントクラスを生成するクラスファクトリ(列のアクセサ、検索メソッドなど)があります。
そしてもちろん、有名なbitbltの例と正規表現の類似物があります。
RTトレーシングJITの情報に基づいて動的に最適化
付加的な環境でのadaスタイルのジェネリック関数のサブタイプの特殊化。
--MarkusQ
ダイナミックリンクは一種の自己修正(絶対ジャンプ位置および/または相対ジャンプ位置へのパッチ適用)です...ただし、通常はO/Sのプログラムローダーによって実行されます。
ニューラルネットワーク は一種の自己修正コードです。
次に、 進化的アルゴリズム があります。
笑-私は2つの機会に自己修正コードを書きました:
自己修正コードが他のコードよりも効率的であるシナリオがあるかもしれないと想像できますが、明らかな飛躍はありません。一般に、これは避けるべきものです-悪夢のデバッグなど-上記のように意図的に難読化しようとしているのでない限り。
Mike Abrashは、しばらく前にDr. Dobb's JournalのPixomaticコードジェネレーターについて説明しました: http://www.ddj.com/architect/184405807 。これは、ソフトウェアの3d dx7(?)互換のラスタライザーです。
独自のスクリプト言語を実装するアプリケーションは、多くの場合これを行います。たとえば、データベースサーバーは、多くの場合、この方法でストアドプロシージャ(またはクエリ)をコンパイルします。
SwiftShaderでの動的コード生成は、CPUにDirect3D9を効率的に実装できるようにする自己変更コードの形式です。