26

少し時間がかかりすぎて、自己修正プログラムを書けないかと思い始めました。そのために、Cで「HelloWorld」を作成し、16進エディターを使用して、コンパイルされた実行可能ファイル内の「HelloWorld」文字列の場所を見つけました。このプログラムを変更して、それ自体を開き、「HelloWorld」文字列を上書きすることはできますか?

char* str = "Hello World\n";

int main(int argc, char* argv) {

  printf(str);

  FILE * file = fopen(argv, "r+");

  fseek(file, 0x1000, SEEK_SET);
  fputs("Goodbyewrld\n", file);      
  fclose(file);    

  return 0;
}

これは機能しません。これを2つの別々のプログラム(「HelloWorld」とそれを変更するもの)に分割でき、正常に機能するため、それ自体を開くのを妨げる何かがあると思います。

編集:私の理解では、プログラムを実行すると、RAMに完全にロードされます。したがって、ハードドライブ上の実行可能ファイルは、すべての目的と目的のためにコピーです。なぜそれ自体を変更することが問題になるのでしょうか?

回避策はありますか?

ありがとう

4

9 に答える 9

32

Windows では、プログラムが実行されると、Windows のメモリ マップ ファイル関数を使用して、*.exeファイル全体がメモリにマップされます。これは、ファイルが一度にすべて読み込まれるとは限らず、ファイルのページがアクセスされるたびにオンデマンドで読み込まれることを意味します。

ファイルがこのようにマップされている場合、別のアプリケーション (それ自体を含む) は、実行中に同じファイルに書き込んで変更することはできません。(また、Windows では実行中の実行可能ファイルの名前を変更することもできませんが、Linux や inode ベースのファイルシステムを使用するその他の Unix システムでは可能です)。

メモリにマップされたビットを変更することは可能ですが、これを行うと、OS は「コピー オン ライト」セマンティクスを使用して変更を行います。これは、基になるファイルがディスク上で変更されるのではなく、ページのコピーが変更されることを意味します( s) 変更を加えてメモリ内に作成されます。ただし、これを行う前に、通常、問題のメモリの保護ビットをいじる必要があります (例: VirtualProtect)。

かつては、非常に制約のあるメモリ環境にある低レベルのアセンブリ プログラムでは、自己変更コードを使用するのが一般的でした。しかし、私たちは同じ制約のある環境で実行していないため、これを行う人はもういません。最新のプロセッサには長いパイプラインがあり、その下からコードを変更し始めると非常に混乱します。

于 2010-10-10T03:08:17.343 に答える
6

Windows を使用している場合は、次の操作を実行できます。

ステップバイステップの例:

  1. 保護VirtualProtect()を使用して、変更するコード ページを呼び出します。PAGE_WRITECOPY
  2. コード ページを変更します。
  3. 保護VirtualProtect()を使用して、変更されたコード ページを呼び出します。PAGE_EXECUTE
  4. コールしFlushInstructionCache()ます。

詳細については、メモリ内の実行可能コードを変更する方法(アーカイブ: 2010 年 8 月)を参照してください。

于 2010-11-23T00:36:03.920 に答える
4

これは、オペレーティングシステムに大きく依存します。一部のオペレーティングシステムはファイルをロックするため、どこかに新しいコピーを作成して不正行為を試みることができますが、プログラムの別のコンプを実行しているだけです。

iPhoneなど、他のオペレーティングシステムはファイルのセキュリティチェックを行うため、ファイルの書き込みは大変な作業になり、さらに読み取り専用ファイルとして存在します。

他のシステムでは、ファイルがどこにあるかさえわからない場合があります。

于 2010-10-10T03:04:02.550 に答える
4

現在のすべての答えは、多かれ少なかれ、今日、自己変更型のマシンコードを簡単に実行することができなくなっているという事実を中心に展開しています。私はそれが今日のPCに基本的に当てはまることに同意します。

ただし、実際に独自の自己変更コードが動作していることを確認したい場合は、いくつかの可能性があります。

  • マイクロコントローラーを試してみてください。単純なものには高度なパイプラインがありません。私が見つけた最も安くて速い選択はMSP430USB-Stickです

  • エミュレーションに問題がない場合は、パイプライン化されていない古いプラットフォーム用のエミュレーターを実行できます。

  • 楽しみのためだけに自己変更コードが必要な場合は、 Corewarsで自己破壊コード(より正確には敵を破壊する)をさらに楽しむことができます。

  • あなたがCからLisp方言を言うことをいとわないなら、コードを書くコードはそこで非常に自然です。意図的に小さくしたスキームをお勧めします。

于 2010-10-10T12:49:58.367 に答える
2

x86 環境でこれを行うことについて話している場合、不可能ではないはずです。ただし、x86 命令は可変長であるため、注意して使用する必要があります。長い命令は後続の命令を上書きする可能性があり、短い命令は上書きされた命令の残りのデータを残し、ノープする必要があります (NOP 命令)。

x86 が最初に保護されたとき、インテルのリファレンス マニュアルでは、XO (実行のみ) 領域へのアクセスをデバッグするために次の方法を推奨していました。

  1. 新しい空のセレクターを作成します (far ポインターの「高い」部分)
  2. その属性を XO 領域の属性に設定します
  3. その内容のみを確認したい場合は、新しいセレクターのアクセス プロパティを RO DATA に設定する必要があります。
  4. データを変更する場合は、アクセス プロパティを RW DATA に設定する必要があります

したがって、問題の答えは最後のステップにあります。デバッガーが行うブレークポイント命令を挿入できるようにする場合は、RW が必要です。80286 よりも新しいプロセッサには内部デバッグ レジスタがあり、ブレークポイントが発行される可能性がある非侵入型監視機能を有効にします。

Windows は、Win16 以降、これを行うためのビルディング ブロックを利用できるようにしました。それらはおそらくまだそのままです。Microsoft は、このクラスのポインター操作を「サンク」と呼んでいると思います。


私はかつて、DOS 用の PL/M-86 で非常に高速な 16 ビット データベース エンジンを作成しました。Windows 3.1 (80386s 上で動作) が登場したとき、私はそれを Win16 環境に移植しました。利用可能な 32 ビット メモリを利用したかったのですが、利用可能な PL/M-32 (または Win32) がありませんでした。

私のプログラムが次の方法でサンクを使用した問題を解決するために

  1. 構造体を使用して定義された 32 ビット far ポインター (sel_16:offs_32)
  2. グローバル メモリを使用して 32 ビット データ領域 (<=> >64KB サイズ) を割り当て、それらを 16 ビット far ポインタ (sel_16:offs_16) 形式で受信
  3. セレクターをコピーして構造体にデータを入力し、16 ビットの乗算と 32 ビットの結果を使用してオフセットを計算します。
  4. 命令サイズオーバーライドプレフィックスを使用して、ポインター/構造体を es:ebx にロードしました
  5. 命令サイズとオペランド サイズのプレフィックスの組み合わせを使用してデータにアクセスした

メカニズムにバグがなくなると、問題なく機能しました。私のプログラムが使用した最大のメモリ領域は 2304*2304 の倍精度で、約 40MB になりました。今日でも、これを「大きな」メモリ ブロックと呼んでいます。1995 年には、典型的な SDRAM スティック (128 MB PC100) の 30% でした。

于 2011-01-24T03:13:47.490 に答える
1

多くのプラットフォームでこれを行う移植性のない方法があります。WriteProcessMemory()Windows では、たとえば でこれを行うことができます。ただし、2010 年には通常、これを行うのは非常に悪い考えです。これは、スペースを節約するためにアセンブリでコーディングし、これを行う DOS の時代ではありません。正しく理解するのは非常に難しく、基本的には安定性とセキュリティの問題を求めています。デバッガーのような非常に低レベルのことをしているのでない限り、これを気にしないでください。

于 2010-10-10T03:06:34.010 に答える
1

自己変更コードは、ファイルではなくメモリ内の変更に使用されます (UPX のようなランタイム アンパッカーのように)。また、プログラムのファイル表現は、相対仮想アドレス、再配置の可能性、およびほとんどの更新に必要なヘッダーへの変更 (たとえば、ファイル内のデータ セグメントを拡張する必要がある を にHello world!変更するなど) のため、操作がより困難です。longer Hello World

最初に暗記することを学ぶことをお勧めします。ファイルの更新の場合、最も単純で一般的な方法は、プログラムのコピーを実行して、元のプログラムを変更することです。

編集:そして、自己変更コードが使用される主な理由を忘れないでください:

1) 難読化。実際に実行されるコードは、ファイルの単純な静的解析で表示されるコードではありません。

2) パフォーマンス、JIT のようなもの。

実行可能ファイルを変更してもメリットはありません。

于 2010-10-10T10:41:59.627 に答える
0

Windowsで操作している場合は、実行中にファイルが変更されないようにファイルがロックされると思います。そのため、アップデートをインストールするためにプログラムを終了する必要があることがよくあります。Linuxシステムでは同じことは当てはまりません。

于 2010-10-10T02:59:34.430 に答える
0

アプリがユーザー空間で実行される新しいバージョンの Windows CE (少なくとも 5.x 以降) では、(すべてのアプリがスーパーバイザー モードで実行される以前のバージョンと比較して)、アプリはそれ自体の実行可能ファイルを読み取ることさえできません。

于 2010-10-10T11:02:57.353 に答える