2

私は職場で無料の Digital Mars Compiler をいじり回しており (いたずらなことはわかっています)、コンパイルされた関数を検査し、学習目的でバイト コードを調べるためのコードを作成しました。その機能。ただし、MSVC++ で同じメソッドを再作成することは惨めに失敗し、得られた結果は非常に混乱しています。私はこのような機能を持っています:

unsigned int __stdcall test()
{
  return 42;
}

その後、私は次のことを行います。

unsigned char* testCode = (unsigned char*)test;

この場合、C++ static_cast を動作させることができないようです (コンパイラ エラーがスローされます)。したがって、C スタイルのキャストですが、それは重要なことではありません。また、参照 &test を使用してみました。しかし、それは何の助けにもなりません。

ここで、testCode が指すメモリの内容を調べると、有効なコードのようにも見えず、そこにデバッグ ブレークポイントが残っているため、混乱します...次のようになります (ターゲットは IA です) -32):

0xe9、0xbc、0x18、0x00、0x00、0xcc...

これは明らかに間違っています。0xe9 は相対ジャンプ命令であり、0xbc バイト先を見ると次のようになります。

0xcc、0xcc、0xcc...

つまり、割り当てられていないメモリまたは未使用のメモリに対して予想されるように、メモリはデバッグ ブレークポイント オペコードに初期化されます。

42 を返す関数に期待するのは次のようなものです。

0x8b、0x2a、0x00、0x00、0x00、0xc3

または少なくともいくつかの種類の mov の後に ret (0xc2、0xc3、0xca または 0xcb) が続き、少し下に

MSVC++ は、セキュリティ上の理由からこの種のことを行うのを防ぐための措置を講じていますか、それとも私は愚かなことをしていて、それに気づいていませんか? この方法は、DMC をコンパイラとして使用するとうまくいくようです...

また、逆方向 (バイトの実行) に問題がありますが、根本的な原因は同じであると思われます。

ヘルプやヒントをいただければ幸いです。

4

4 に答える 4

2

あなたが望むキャストのために:

unsigned char* testCode = reinterpret_cast<unsigned char*>( test );

[プロジェクト] -> [プロパティ] -> [C/C++] -> [全般] で、デバッグ情報の形式を「エディット コンティニュのプログラム データベース (/ZI)」から「プログラム データベース (/Zi)」に切り替えます。プログラムの実行中にデバッガーが関数を再構築してホットパッチできるように、コンパイラーにジャンプコードを挿入させるのはその設定だと思います。おそらく「最小限の再構築を有効にする」もオフにします。

MSVC でコードを検査するより簡単な方法は、単純にブレーク ポイントを設定して逆アセンブリを検査することです (行を右クリックし、ポップアップ メニューから [Goto disassembly] を選択します。ソース コードで逆アセンブリに注釈が付けられるので、各行が何にコンパイルされているかを確認できます。

于 2009-02-06T22:38:48.507 に答える
2

推測することしかできませんが、デバッグ ビルドを検査していると確信しています。デバッグ モードでは、MSVC++ コンパイラはすべての呼び出しをジャンプ スタブへの呼び出しに置き換えます。これは、すべての関数が実際の関数へのジャンプで始まることを意味し、これがまさにここで直面していることです。
周囲の 0xCC バイトは実際にはブレークポイント命令です。これは、実行すべきではないコードを実行している場合に、接続されている可能性のあるデバッガーを起動するためです。
リリース ビルドで同じことを試してください。これは期待どおりに機能するはずです。

編集: これは、実際にはリンカー設定 /INCREMENTAL の影響を受けます。あなたが説明している効果がリリースビルドに表示されない理由は、何らかの最適化がオンになっている場合、これらのジャンプスタブが単純に最適化されるためです (もちろん、通常はリリースビルドの場合です)。

于 2009-02-06T22:25:49.453 に答える