5

簡単な説明:

アセンブリ プログラムのセグメントの最初の行にブレークポイントを設定して.CODEも、プログラムの実行が停止しません。

質問:

アセンブリで記述されたプログラムの最初の行で、Visual Studio のデバッガーがブレークポイントの作成に失敗することを許可するのはどうですか? これはデバッガーの奇妙な点ですか、マルチバイト命令で中断する場合ですか、それとも私が何かばかげたことをしているだけですか?

詳細:

次のアセンブリ プログラムを Visual Studio でコンパイルして実行しています。

; Tell MASM to use the Intel 80386 instruction set.
.386
; Flat memory model, and Win 32 calling convention
.MODEL FLAT, STDCALL
; Treat labels as case-sensitive (required for windows.inc)
OPTION CaseMap:None

include windows.inc
include masm32.inc
include user32.inc
include kernel32.inc
include macros.asm

includelib masm32.lib
includelib user32.lib
includelib kernel32.lib

.DATA
    BadText     db      "Error...", 0
    GoodText    db      "Excellent!", 0

.CODE
main PROC
        ;int 3           ; <-- If uncommented, this will not break.
        mov ecx, 6       ; <-- Breakpoint here will not hit.
        xor eax, eax     ; <-- Breakpoint here will.
_label: add eax, ecx
        dec ecx
        jnz _label
        cmp eax, 21
        jz _good
_bad:   invoke StdOut, addr BadText
        jmp _quit
_good:  invoke StdOut, addr GoodText
_quit:  invoke ExitProcess, 0
main ENDP
END main

メイン関数の最初の行にブレークポイントを設定しようとするとmov ecx, 6、それは無視され、プログラムは停止せずに実行されます。xor eax, eaxその後の行、または後続の行にブレークポイントを設定した場合にのみ、ブレークポイントがヒットします。

int 3関数の最初の行としてソフトウェア ブレークポイントを挿入しようとしましたが、これも無視されます。

最初に奇妙な点に気付きました。ブレークポイントの 1 つにヒットした後に逆アセンブリを表示すると、次のようになります。

01370FFF  add         byte ptr [ecx+6],bh  
--- [Path]\main.asm 
        xor eax, eax
00841005  xor         eax,eax  --- <-- Breakpoint is hit here
_label: add eax, ecx
00841007  add         eax,ecx  
        dec ecx
00841009  dec         ecx  
        jnz _label
0084100A  jne         _label (841007h)  
        cmp eax, 21
0084100C  cmp         eax,15h  

ここで興味深いのxorは、Visual Studio から見れば、これが私のプログラムの最初の操作であるということです。行がありませんmove ecx, 6。私のソースが開始すると思われる場所のすぐ上に、実際にはecx6 に設定されている行があります。したがって、私のプログラムの実際の開始は、逆アセンブルに従って壊れています。

プログラムの最初の行を作成するとint 3、コードが逆アセンブリにある場所の上に表示される行は次のようになります。

00F80FFF  add         ah,cl

回答の1つで提案されているように、ASLRをオフにしましたが、逆アセンブリはもう少し安定しているようです:

.CODE
main PROC
        ;mov ecx, 6
        xor eax, eax
00401000  xor         eax,eax  --- <-- Breakpoint is present here, but not hit.
_label: add eax, ecx
00401002  add         eax,ecx  --- <-- Breakpoint here is hit.
        dec ecx
00401004  dec         ecx  

完全なプログラムは逆アセンブルで表示されますが、問題は解決しません。私のプログラムは予想されるアドレスで開始し、逆アセンブリ最初のブレークポイントが表示されますが、それでもスキップされます。最初の行としてan を配置しint 3ても、次の行になります。

00400FFF  add         ah,cl  

実行を停止せず、逆アセンブリでプログラムのビュー再びマングルします。私のプログラムの次の行は location00401001にあり、これは 1 バイトの命令なので理にかなっていると思いますint 3が、なぜ逆アセンブリで消えてしまったのでしょうか?

「ステップ イン (F11)」コマンドを使用してプログラムを開始しても、最初の行で中断できません。実際、ブレークポイントがない場合、F11 でプログラムを開始しても、実行はまったく停止しません。

ここで詳しく説明した以外に、問題を解決するために他に何ができるか本当にわかりません。これは、アセンブリとデバッガーに関する私の現在の理解を超えています。

4

3 に答える 3

3

01370FFF バイト ptr を追加 [ecx+6],bh

少なくとも、1 つの謎を解き明かすことができます。アドレス 0x1370fff に注意してください。CODE セグメントがそのようなアドレスで始まることはありません。セグメントは 0x1000 の倍数のアドレスで始まります。これにより、開始アドレスの最後の 3 桁の 16 進数が常に 0 になります。デバッガーは混乱し、間違ったアドレスでコードの逆アセンブルを開始しました。実際の開始アドレスは 0x1371000 です。0x1370fff に 0 があるため、逆アセンブリの開始はうまくいきません。これはマルチバイト ADD 命令です。そのため、誤って実際のマシン コードの命令に追いつくまで、しばらくの間ゴミが表示されます。

あなたはそれを助け、適切なアドレスで逆アセンブルを開始するようにコマンドを与える必要があります. アドレスボックスであるVSで、「0x1371000」と入力します。

もう 1 つの顕著な癖は、開始アドレスの奇妙な値です。プロセスは通常、アドレス 0x400000 から開始されます。ASLR と呼ばれる機能、アドレス空間レイアウトのランダム化がオンになっています。これは、プログラムを予測できない開始アドレスから開始させるウイルス対策機能です。素晴らしい機能ですが、プログラムのデバッグにはまったく役立ちません。このコードをどのように作成したかは明確ではありませんが、無効にするには /DYNAMICBASE:NO リンカー オプションが必要です。

ここで覚えておく必要があるデバッガーのもう 1 つの重要な特徴は、ブレークポイントの設定方法です。コードにパッチを当てて、命令の開始バイトを命令に置き換えますint 3。ブレークポイントがヒットすると、そのバイトはすぐに元のマシン コードの命令バイトに置き換えられます。だからあなたはこれを見ることはありません。マルチバイト命令の途中のように、ブレークポイントを設定するために間違ったアドレスを選択すると、これはうまくいきません。コードが壊れなくなり、変更されたバイトが元の命令を台無しにします。不適切な分解から始めた場合、このトラップに簡単に陥る可能性があります。

さて、これを正しい方法で行います。代わりに、デバッガーの STEP コマンドを使用してデバッグを開始してください。

于 2012-11-01T21:12:12.927 に答える
1

問題の根本が何であるかを発見しましたが、なぜそうなのかわかりません。

別のMASMプロジェクトを作成した後、新しいプロジェクトがプログラムの最初の行で壊れ、逆アセンブリが壊れたり変更されたりしていないように見えることに気付きました。そこで、そのプロパティを元のプロジェクト(デバッグ構成用)と比較しました。私が見つけた唯一の違いは、私の元のプロジェクトではインクリメンタルリンクが無効になっていることでした。具体的に/INCREMENTAL:NOは、リンカーのコマンドラインに追加されました。

このオプションをコマンドラインから削除すると(これによりインクリメンタルリンクが有効になります)、プログラムはデバッグ中に期待どおりに動作します。main逆アセンブリウィンドウに表示されるコードは変更されないままで、プロシージャの最初の行でブレークポイントに到達する可能性があり、int 3命令も最初の行として正しく実行されます。

于 2012-12-05T06:22:53.327 に答える
0

Start Debugging の代わりに F+11 (step into) を押すと、デバッガーは最初の行で停止します。

ブレークポイントの設定が間違っている可能性があります。プロジェクト ディレクトリ内の *.suo ファイルをすべて削除して、すべてのブレークポイントをリセットします。

プロジェクトにメイン関数がある場合、プロジェクトには秘密のヘッダーなどが含まれることに注意してください。実際のエントリ ポイントにブレークポイントを設定するには、Debug + New Breakpoint + Break at Function -> Windows プログラムの場合は wWinMainCRTStartup、コンソール プログラムの場合は mainCRTStartup または wmainCRTStartup を使用します。

于 2012-11-01T20:31:26.720 に答える