M$VC 调试器一个奇怪的BUG

mLee79 2011-07-21 08:43:21
在 VC6 和VS2K5 上试过, 其他版本没试过, 不过可能还是这样子...

#include <stdio.h>

int main()
{
printf( "Hello World!\n" );
__asm int 3;
printf( "Hello World!\n" );
__asm _emit 0CDH;
__asm _emit 03H ;
printf( "Hello World!\n" );
return 0;
}

为什么 CD 03 被M$当成单字节指令了. 这个是比较蛋疼, 为啥米不用 CC 要用 CD 03 , 搞不懂nasm弄的啥飞机...

这个帖子有好点的结果了一起领分: http://topic.csdn.net/u/20110721/03/b85d4dda-0579-4972-9b61-ef0187380726.html
等一周没啥结果就大家平分...


...全文
486 点赞 收藏 58
写回复
58 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
mLee79 2011-07-27
[Quote=引用 57 楼 bokutake 的回复:]

cygwin用的是newlib,Linux下是glibc,可能是这方面有区别。
[/Quote]

这个是在 cygwin 编译的 Ubuntu x64 的交叉编译器,肯定也是用的 eglibc 三。
回复
辰岡墨竹 2011-07-27
cygwin用的是newlib,Linux下是glibc,可能是这方面有区别。
回复
辰岡墨竹 2011-07-27
[Quote=引用 53 楼 mlee79 的回复:]

不是这样子的, WIN 本身处理 CD03 是没有BUG的, 你自己写一个简单的 debugger 验证下就知道 CD03 CC 都工作正常的, 你就不断的 waitfordebugevent + continuedebugevent 就可以让程序一直正常的运行...

这个BUG完全是 M$VC 调试器的BUG, 应该是调试器在处理 EXCEPTION_DEBUG_EVENT 的事件上有瑕疵...

[/Quote]

说不定,在早期Windows有那个Bug,比如95上,纯属推测。现在的版本没有那个问题。
回复
mLee79 2011-07-27
amd64 / arm 版本都能跑了, 过程中发现:

Ubuntu x64 10.04 , gcc 4.4.5 下 ptrace( PTRACE_GETREGS ) 内存越界, 不知道是 gcc 的BUG 还是装的 linux-kernel-header 有问题, 我自己在 cygwin 下编译的交叉编译器 gcc 4.5.0 则没有这个问题...

WIN7 x64 版本把 rdata 段也改成缺省的不可执行, 这个太无聊了吧...

---------------------------------------------------------------

弄了一个 WIN64 到 ELF64 调用约定转换的小玩意, 这样就可以在 win64 下直接调用 elf64 的代码了, win64 的toolchain用的不是很熟, 还是用gcc方便些...

还弄了一套宏, 可以用相同C代码直接动态生成 i386 , arm , win64 , elf64 可以运行的汇编代码, 方便调试啥的...



回复
mLee79 2011-07-26
[Quote=引用 52 楼 redleaves 的回复:]

帮楼主测试了一下,VS2010下还是没法调试这个程序.顺手也测试了一下WinDBG,也不能正确处理这个问题.

不过出错的过程应该和你上面所说的有点区别.
应该是执行int 3后.eip指向了下一条指令.这时eip是+2了的.但调试器收到3号中断,就想当然的认为是int3断点,于是,它尝试恢复eip+2-1位置的代码,然后把eip-1.这时,eip就落到了中断前eip+1的位置.

不过这又让我想起了另一件事.如果用这个技术来做花指令加密,似乎挺合适的...只需要在收到中断以后,按适当的规则恢复现场,从而引起一系列的异常.这些异常刚好又可以当做验证的信号.调试起来肯定很爽...
[/Quote]

这个正是我现在在做的... 我在一个进程里以调试方式启动另一个进程, 然后将本进程要运行的关键代码注入到正在调试的进程中运行... 现在 i386 windows , i386 linux 都可以运行了, 今天开始弄 amd64 , arm 版本的....

回复
mLee79 2011-07-26
[Quote=引用 49 楼 bokutake 的回复:]

HTML code

i. Interrupt 3
When an EXCEPTION_BREAKPOINT (0x80000003) occurs, the eip register has already been advanced to the next instruction, so Windows wants to rewind the eip to point to the pro……
[/Quote]

不是这样子的, WIN 本身处理 CD03 是没有BUG的, 你自己写一个简单的 debugger 验证下就知道 CD03 CC 都工作正常的, 你就不断的 waitfordebugevent + continuedebugevent 就可以让程序一直正常的运行...

这个BUG完全是 M$VC 调试器的BUG, 应该是调试器在处理 EXCEPTION_DEBUG_EVENT 的事件上有瑕疵...

回复
redleaves 2011-07-26
[Quote=引用 19 楼 mlee79 的回复:]
这个出错的原因是 M$VC 吧 CD 03 当成了单字节指令, 它得到断点后, 把 eip += 1 准备运行下一条指令 . 结果下一条指令就成了 03 FF D7 ( 本来 FF D7 是 call edi ) , 然后它就把 03 FF 当成了 add edi , edi 运行, 下一个 D7 成了 xlat 指令, 结果就完全飞了....[/Quote]帮楼主测试了一下,VS2010下还是没法调试这个程序.顺手也测试了一下WinDBG,也不能正确处理这个问题.

不过出错的过程应该和你上面所说的有点区别.
应该是执行int 3后.eip指向了下一条指令.这时eip是+2了的.但调试器收到3号中断,就想当然的认为是int3断点,于是,它尝试恢复eip+2-1位置的代码,然后把eip-1.这时,eip就落到了中断前eip+1的位置.

不过这又让我想起了另一件事.如果用这个技术来做花指令加密,似乎挺合适的...只需要在收到中断以后,按适当的规则恢复现场,从而引起一系列的异常.这些异常刚好又可以当做验证的信号.调试起来肯定很爽...
回复
辰岡墨竹 2011-07-26
也可能是CC和CD 03在效果上的区别,导致OS设计者选用CC,结果做INT 3中断门的时候就想当然了,为了提高效率没有判断源指令。
回复
辰岡墨竹 2011-07-26
嗯,上面贴的是这个,成一行了:
i. Interrupt 3
When an EXCEPTION_BREAKPOINT (0x80000003) occurs, the eip register has already been advanced to the next instruction, so Windows wants to rewind the eip to point to the proper place. The problem is that Windows assumes that the exception is caused by a single-byte "CC" opcode (short form "INT 3" instruction). If the "CD 03" opcode (long form "INT 3" instruction) is used to cause the exception, then the eip will be pointing to the wrong location. The same behaviour can be seen if any prefixes are placed before the short-form "INT 3" instruction. An emulator that does not behave in the same way will be revealed instantly. This technique is used by TryGames.
回复
辰岡墨竹 2011-07-26

i. Interrupt 3
When an EXCEPTION_BREAKPOINT (0x80000003) occurs, the eip register has already been advanced to the next instruction, so Windows wants to rewind the eip to point to the proper place. The problem is that Windows assumes that the exception is caused by a single-byte "CC" opcode (short form "INT 3" instruction). If the "CD 03" opcode (long form "INT 3" instruction) is used to cause the exception, then the eip will be pointing to the wrong location. The same behaviour can be seen if any prefixes are placed before the short-form "INT 3" instruction. An emulator that does not behave in the same way will be revealed instantly. This technique is used by TryGames.


嗯,我觉得不是VS的问题,而是Windows的问题。因为32位模式下INT 3中断处理是Windows内核做的。而且查了一下,发现DEBUG也有同样的问题。DEBUG设计者认为INT 3只能是CC指令造成的,所以不会去看到底是什么指令,而直接去修改EIP指针。
估计微软的早期OS设计者在设计INT 3中断处理时也想当然,因为Intel和微软的编译器不会生成CD 03,所以设计时估计也和DEBUG一样。同理VS也只能按着这个方式来。我不觉得是故意留下Anti-debug的,难道微软设计编译器和Debug等都是同一组人么?
所以应该是一种为了兼容性,而不得已为之的。
回复
情歌而已 2011-07-25
强势围观,坐等结果
回复
yk84 2011-07-23
我来混分的
回复
mLee79 2011-07-23
在 2K5 下调试64位代码还是一样的飞...
回复
nevergone 2011-07-22
这个bug在《软件调试》里面有提到过 确实是VC编译器的BUG
回复
Jxiaoshen 2011-07-22
顶顶更健康~
回复
[Quote=引用 39 楼 luciferisnotsatan 的回复:]

cout<<"abc"<<"xxx"<<"sss"<<"sss";
把这种一连串的 <<翻成 operator<<(operator<<)这样的函数调用来写,写着写着,能把vc2005弄崩了。
[/Quote]
估计是输入补全那个功能上的bug。
回复
cout<<"abc"<<"xxx"<<"sss"<<"sss";
把这种一连串的 <<翻成 operator<<(operator<<)这样的函数调用来写,写着写着,能把vc2005弄崩了。
回复
mLee79 2011-07-22
再顶上去.
回复
pengzhixi 2011-07-22
vs2008跑挂了,但是指向了第一条int 3指令。不是后面的__asm _emit 0CDH;
__asm _emit 03H ;
回复
mLee79 2011-07-22
[Quote=引用 43 楼 delphiguy 的回复:]

可惜我只装了VC++2010的编译器和库,没装IDE,验证不了。不过用TD调试嵌入CD 03指令的exe是没有问题的。
[/Quote]

好像是M$VC每个版本都有这个问题, 其他的调试器还没发现这个毛病..
回复
加载更多回复
相关推荐
发帖
其它技术问题
创建于2007-09-28

3849

社区成员

C/C++ 其它技术问题
申请成为版主
帖子事件
创建了帖子
2011-07-21 08:43
社区公告
暂无公告