5

これが以前に尋ねられなかったことを本当に願っていますが、私のグーグルは何も思いつかなかったので、私は尋ねようと思いました.

ゲームに DLL を挿入し、特定のイベントが発生したときに表示される特定の文字列を編集する小さなスクリプトを作成しています。この文字列がメモリ内に存在する場所を見つけ、実行時にそれを見つけるための基本的な sigscanning 関数を作成しました。私の質問は、開始アドレスが与えられた場合、この文字列を自分の特定の文字列に置き換える方法/できますか?

たとえば、文字列が「I love pancakes」で、「Pancakes are bad, waffles are best!」に置き換えたいとします。どうすればそれを行うことができますか?

ありがとう!

そうそう、問題があれば、ソースの文字列は const char です。そうではないと確信していますが、その情報を追加しても害はありません!

4

2 に答える 2

2

置き換えたい文字列が少なくともその置換と同じくらい長い場合、それは簡単です。その場で置き換えます。そうでなければ、パンケーキが嫌いでワッフルが好きだと確実に宣言することはできません.

于 2012-11-14T03:43:01.380 に答える
1

ご指摘のとおり、文字列を参照するアセンブリ手順は通常、次のようになります。

push offset aString

組み立ててリンクした後、これは実際のアドレスに解決されます。

push 0x00ABCDEF

これにより、次の 2 つのオプションが提供されます。

  • データの書き込み:の内容を変更しますaString(つまり、 が指すメモリ0x00ABCDEF)
  • コードを書く:への参照を変更するaString

書き込みデータ

標準 C 文字列リテラル (メモリ内の文字の不変配列) を含むソース コードがコンパイルされると、通常、実行時に文字列は他のすべての読み取り専用データと共に読み取り専用ページにマップされます。このデータは通常、プログラムのメモリ フットプリントを削減するために連続してパックされます。これは、より大きな文字列を書き込もうとしてヒットしている問題です。次のデータを上書きすると、この上書きされたデータへの参照はすべて、大きな文字列の中央を指すようになります。

データを変更してより長い文字列を書き込むことは簡単ではありません。これは、元の機能的な動作を失わないようにするために、文字列の後のすべてのデータを前方にシフトする必要があるためです。その後、シフトされたデータへのすべての参照を更新する必要があります (その一部はポインター演算で動的に計算される場合があります)。私が言うように、このプロセスは自明ではありません - 完全な (もしあれば) シンボリック情報なしで、再配置に関してリンカーのタスクを再現しようとしています。

コードを書く

簡単な方法は、新しい文字列を任意の場所に書き込むことです。これは、プロセスで既に使用されていないが予約済みのメモリ (一般に「コード ケーブ」と呼ばれます) であるか、DLL を挿入するときにマップする文字列リテラルである可能性があります。または、注入後に実行時にこれを動的に割り当てることもできます。

次のステップは、すべての参照を見つけてaString、代わりに新しい文字列を参照するように置き換えることです。

ボーナス方法:)

このレベルでリバース エンジニアリングを掘り下げているため、迂回/傍受/インストルメンテーションの概念に出くわした可能性があります。ここで同様のアプローチを適用して、すべての参照をインターセプトし、実行時にリダイレクトすることができます。これにより、上記の「コードを書く」方法よりもパフォーマンスが大幅に低下しますが、すべてのアクセスが捕捉され、リダイレクトされることが保証されます。

アクセス時のハードウェア ブレークポイントは、文字列が指すデータに設定されます。ブレークポイントがトリガーされると、一部のレジスタが文字列のアドレスを保持します。アセンブリでは、これは次のようになります。

mov esi, 0x00ABCDEF
...

最初の文字にアクセスすると、コードは次のようになります。

mov al, byte ptr ds:[esi]

ブレークポイントに到達すると、スレッド コンテキスト ( SetThreadContextWindows の場合) を設定esiして、新しい文字列を指すように値を変更できます。

于 2012-12-27T21:37:37.103 に答える