Visual Studio 只在第二行汇编时中断?

2023-11-23

简短描述:

在我的第一行设置断点.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

如果我尝试在 main 函数的第一行设置断点,mov ecx, 6,它被忽略,程序继续执行。只有当我在那之后将断点设置在行上时才会命中断点,xor eax, eax,或任何后续行。

我什至尝试过插入软件断点,int 3,作为函数的第一行,它也被忽略。

我注意到的第一件事很奇怪:在遇到一个断点后查看反汇编结果如下:

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。在它认为我的源代码开始的地方的正上方是实际设置的行ecx到 6. 因此,根据反汇编,我的程序的实际启动已被破坏。

如果我编写程序的第一行int 3,上面出现的行是我的代码在反汇编中的位置:

00F80FFF  add         ah,cl

正如其中一个答案所建议的,我关闭了 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  

完整的程序在反汇编中可见,但问题仍然存在。尽管我的程序从预期的地址开始,and反汇编中显示第一个断点,但它仍然被跳过。放置一个int 3因为第一行仍然会产生以下行:

00400FFF  add         ah,cl  

并且不停止执行,and再次在反汇编中重新破坏我的程序的视图。我的程序的下一行位于位置00401001,我认为这是有道理的,因为int 3是一条单字节指令,但为什么它会在反汇编中消失呢?

即使使用“Step Into (F11)”命令启动程序也不允许我在第一行中断。事实上,在没有断点的情况下,使用 F11 启动程序根本不会停止执行。

除了我在这里详细介绍的内容之外,我不太确定还能尝试什么来解决该问题。这超出了我目前对汇编和调试器的理解。


01370FFF 添加字节指针 [ecx+6],bh

至少我可以解释一个谜团。请注意地址 0x1370fff。 CODE 段永远不会从这样的地址开始,段从 0x1000 倍数的地址开始。这使得起始地址的最后 3 个十六进制数字始终为 0。调试器感到困惑并开始在错误的地址反汇编代码,相差 1。实际的起始地址是0x1371000。反汇编一开始很糟糕,因为 0x1370fff 处有一个 0。这是一条多字节 ADD 指令。因此它会显示一段时间的垃圾,直到它偶然赶上真正的机器代码指令。

您需要帮助它并给它一个命令以在正确的地址开始反汇编。在 VS 的地址框中,键入“0x1371000”。

另一个值得注意的怪癖是起始地址的奇怪值。进程通常从地址 0x400000 开始。您启用了一项名为 ASLR 的功能,即地址空间布局随机化。它是一种防病毒功能,使程序从不可预测的起始地址启动。不错的功能,但它并不能完全帮助调试程序。目前尚不清楚您如何构建此代码,但您需要 /DYNAMICBASE:NO 链接器选项将其关闭。

您需要记住的调试器的另一个重要怪癖是它们设置断点的方式。他们这样做是通过patching代码,将指令的起始字节替换为int 3操作说明。当断点命中时,它会快速用原始机器代码指令字节替换该字节。所以你永远不会看到这个。如果您选择错误的地址来设置断点(例如在多字节指令的中间),则会出错。现在它不再破坏代码,改变的字节会弄乱原始指令。当你从一个糟糕的反汇编开始时,你很容易陷入这个陷阱。

好吧,以正确的方式做到这一点。使用调试器的 STEP 命令开始调试。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Visual Studio 只在第二行汇编时中断? 的相关文章

随机推荐