简短的描述:
在程序集中的.CODE
段的第一行上设置断点不会停止程序的执行。
问题是:
如果Visual的调试器允许它在以程序集中编写的程序的第一行创建断点,那么怎么办?这是调试器的奇怪之处,是多字节指令中断的情况,还是我只是在做傻事呢?
详情如下:
我在Visual中编译和运行了以下汇编程序:
; 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
作为函数的第一行,它也被忽略了。
我注意到的第一件事很奇怪:在碰到一个断点后查看反汇编会给我以下信息:
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
有趣的是,在Visual看来,xor
是我程序中的第一个操作。缺席的是行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
完整的程序在拆卸过程中是可见的,但问题仍然存在。尽管我的程序从预期的地址开始,和(反汇编中显示的第一个断点)仍然被跳过。将int 3
作为第一行仍然会产生以下行:
00400FFF add ah,cl
并且不会停止执行,并在反汇编中重新破坏我的程序的视图。我的程序的下一行是在location 00401001
,我认为这是有意义的,因为int 3
是一个单字节的指令,但是为什么它会在反汇编中消失呢?
即使使用'Step (F11)‘命令启动程序,也不允许我中断第一行。事实上,在没有断点的情况下,使用F11启动程序根本不会停止执行。
我不太确定我还能做些什么来解决这个问题,除了我在这里所详述的以外。这超出了我目前对程序集和调试器的理解。
发布于 2012-11-01 21:12:12
01370FFF添加字节ptr ecx+6,bh
至少我能解释一个谜团。注意地址,0x1370fff。代码段从不从这样的地址开始,段以0x1000的倍数开始。这使得开始地址的最后三个十六进制数字总是0。调试器被弄糊涂了,开始在错误的地址上解压代码,只有一个地址。实际开始地址是0x1371000。因为在0x1370fff处有0,所以反汇编开始得很糟糕。这是一个多字节的添加指令。因此,它会显示垃圾一段时间,直到意外地赶上真正的机器代码指令。
您需要帮助它,并给它一个命令开始分解在适当的地址。在VS中,输入"0x1371000“。
另一个值得注意的怪癖是起始地址的奇怪价值。进程通常从地址0x400000开始。您有一个名为ASLR的功能打开,地址空间布局随机化。这是一个反病毒功能,使程序从一个不可预测的开始地址开始.不错的功能,但它并不完全帮助调试程序。还不清楚是如何构建这段代码的,但是需要/DYNAMICBASE:NO链接器选项来关闭它。
您需要记住的另一个重要的调试器怪癖是它们设置断点的方式。这样做的方法是修补代码,用int 3
指令替换指令的起始字节。当断点命中时,它会迅速将字节替换为原始机器代码指令字节。所以你从来没见过这个。如果您选择了错误的地址来设置断点,就会出错,就像在多字节指令的中间。它现在不再破坏代码,修改后的字节会扰乱原始指令。当你开始做一个糟糕的拆卸时,你很容易就会掉进这个陷阱。
好吧,这样做是对的。使用调试器的STEP命令开始调试。
https://stackoverflow.com/questions/13080069
复制相似问题