C语言可以捕获诸如int3这种系统异常么?

w_anthony 2009-01-04 02:34:43
答案肯定的,最不济就是先用C++写一段try…catch,然后反汇编,把代码抄过来,当然我问的不是指这种暴力手段。

C的setjmp和longjmp确实和异常处理很像,但是它们并不是可以直接捕获系统异常的东西,比如_asm int 3。

另外这帖http://bbs.bccn.net/thread-245925-1-1.html看过了,他的代码抄过来直接编译运行,却还是异常出错。
反汇编C++的try…catch根本没看见API调用,而这帖用到了API,所以也不知道是他搞错了,还是我理解错了。
所以直接让我看这帖的就免了,如果可以解释一下,正常跑起来,那是欢迎的。

当然直接给出一段捕获int 3异常的C语言代码,那就更好了,多谢各位!
...全文
732 20 打赏 收藏 转发到动态 举报
写回复
用AI写文章
20 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
mark,学习来了
  • 打赏
  • 举报
回复
mark,学习来了
  • 打赏
  • 举报
回复
up学习
w_anthony 2009-01-05
  • 打赏
  • 举报
回复
用OD跟踪了n遍,终于弄明白了,C++和C都是用SetUnhandledExceptionFilter这个API去捕获系统异常的!!!
当发生异常的时候,会调用ntdll中的一个函数,在这个函数里面会检查回调函数的注册情况,如果已经调用了SetUnhandledExceptionFilter进行注册,就会回调之。

1、C++在进入main之前就已经调用了SetUnhandledExceptionFilter来注册异常回调函数,而try…catch实际上只是在特定的内存位置写上一些与这次捕获相关的信息,真正出异常的时候,还是回调之前注册的函数,在那个函数内部,会读取写在那个内存位置的数据,然后进行异常处理,出了try…catch以后,就会将这个内存位置的数据还原,所以在C++的try…catch这里看不到API调用的。
至于为什么无法捕获int 3中断,这个跟踪了n遍,也没看出什么头绪,初步估计可能是那个回调函数不认为int 3是可以处理的异常,结果直接返回EXCEPTION_CONTINUE_SEARCH了吧,这样可以解释为什么搞不定int 3。
2、C没有异常处理,所以只能自己动手,主动调用SetUnhandledExceptionFilter来注册异常回调函数。至于为什么调试状态下,无法正常工作,也已经差不多弄明白了。通过OD的HideOD插件设置,发现Hook掉ZwQueryInformationProcess就可以正常工作,也就是说,ntdll中的那个回调函数,应该在某一个地方调用了ZwQueryInformationProcess检测当前进程的信息,如果发现有调试器,就不会再去处理异常了。异常处理比较原始,也正因为原始,所以可以捕获int 3的中断。

下面送上一个完整的C的异常处理代码,不能调试运行,编译完毕后,直接运行exe。

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <setjmp.h>

jmp_buf mark;

long WINAPI ExceptionFilter(EXCEPTION_POINTERS* lParam) //发生异常后,最终会跑到这里来
{
longjmp(mark, 1); //跳回到setjmp的位置,并且返回值会是1
return 1;
}

int main(int argc, char** argv[])
{
LPTOP_LEVEL_EXCEPTION_FILTER lpOldExceptionFilter = NULL;
int jmpret = 0;
jmpret = setjmp(mark); //记录当前的各个寄存器的信息,此刻返回值会是0
if (jmpret == 0)
{
lpOldExceptionFilter = SetUnhandledExceptionFilter(ExceptionFilter); //注册异常回调函数
_asm int 3;
printf("正常!\r\n");
}
SetUnhandledExceptionFilter(lpOldExceptionFilter); //还原原先的异常回调函数
if (jmpret != 0) //jmpret不是0代表发生过异常
{
printf("异常!\r\n");
}
system("PAUSE");
return 0;
}


xianyuxiaoqiang 2009-01-05
  • 打赏
  • 举报
回复
BluntBlade 2009-01-05
  • 打赏
  • 举报
回复
C++的异常和异常处理都是语言级别的东西,应该不会涉及API层。
有些硬件异常也应该没有C++中软件异常的直接对应物。
考虑一下在Windows上用SEH捕获硬件异常后,转成C++的软件异常,然后在C中仿真try{} catch{}的行为?
至于int 3,是一个特殊的用于调试的硬件中断,在调试器中和调试器外动作不同是正常的。
hhyttppd 2009-01-05
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 w_anthony 的回复:]
看过10L的测试结果后,我也再次测试了一下,这台机与中午的那台不同,系统XP SP3,编译器VS2003,测试结果是这样的:
1、用c++的try…catch写的程序,确实捕捉不了int 3中断,试了试int 1中断之类的其他各种异常手段,成功捕捉。
如果你的DEBUG能捕捉int 1中断,但是Release捕捉不了,那是因为编译器自作聪明把try…catch优化没掉了,在项目属性的C/C++那一栏的命令行加上/EHa可以防止出现出现这种情况。
这个可能跟调试器的断…
[/Quote]

int 3会被调试器当做断点而捕获.
过去的我 2009-01-05
  • 打赏
  • 举报
回复
异常处理没你想象的那么简单啊..你的理解是片面的.
w_anthony 2009-01-04
  • 打赏
  • 举报
回复
看过10L的测试结果后,我也再次测试了一下,这台机与中午的那台不同,系统XP SP3,编译器VS2003,测试结果是这样的:
1、用c++的try…catch写的程序,确实捕捉不了int 3中断,试了试int 1中断之类的其他各种异常手段,成功捕捉。
如果你的DEBUG能捕捉int 1中断,但是Release捕捉不了,那是因为编译器自作聪明把try…catch优化没掉了,在项目属性的C/C++那一栏的命令行加上/EHa可以防止出现出现这种情况。
这个可能跟调试器的断点是用int 3实现的有关,直接运行也是一样出错,不知道白天那台机怎么就可以了……
2、重新试了一下那帖的SetUnhandledExceptionFilter,结果发现使用VC调试的情况下,不管是什么异常,都不能捕获,但如果直接运行,却可以捕获,即使是int 3也能捕获。
3、不过这两者的实现原理似乎大相径庭,C++的try…catch什么API都没用到就实现了异常捕获,而C的这个需要借助于API来完成。而RaiseException是主动抛出异常才会用到,显然不会在捕获里面用到。
zenny_chen 2009-01-04
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 jcwKyl 的回复:]
关注。
一点我的经验:c++中的try-catch用了RaiseException这个Win32 API,这是我以前调试c++的异常处理时追踪发现的。另外,楼主给的那个链接http://bbs.bccn.net/thread-245925-1-1.html上的代码,我直接复制过来运行了,可以捕获int 3异常:

C/C++ code
#include <stdio.h>
#include <windows.h>

int i=0;
int *p=NULL;

long WINAPI ExceptionFilter(EXCEPTION_POINTERS * lParam)
{
puts("DADA...");

[/Quote]

哦。如果真是这样的话,那么C++的异常捕获确实对效率会带来一定的影响。
jcwKyl 2009-01-04
  • 打赏
  • 举报
回复
关注。
一点我的经验:c++中的try-catch用了RaiseException这个Win32 API,这是我以前调试c++的异常处理时追踪发现的。另外,楼主给的那个链接http://bbs.bccn.net/thread-245925-1-1.html上的代码,我直接复制过来运行了,可以捕获int 3异常:

#include <stdio.h>
#include <windows.h>

int i=0;
int *p=NULL;

long WINAPI ExceptionFilter(EXCEPTION_POINTERS * lParam)
{
puts("DADA...");
return 1;
}

int main()
{
SetUnhandledExceptionFilter(ExceptionFilter);
__asm int 3;
return 0;
}

上面这段代码在我电脑上运行,输出如下:
DADA...
请按任意键继续. . .
我的系统是Windows XP SP2, VC2008。
反倒是在我的电脑上c++的try-catch不能捕获int 3异常。
过去的我 2009-01-04
  • 打赏
  • 举报
回复
异常处理设计的知识很丰富的,至于他写的我以为他自己也没完全理解,相关书籍的话,请参阅<加密与解密3> 中的第11章有关结构化异常处理的部分, 和 虚拟机部分对c,c++ 编译实现的分析,其实没你想象当中简单,也不是看看汇编码就能理解的
过去的我 2009-01-04
  • 打赏
  • 举报
回复
对c++ 不是很了解,windows提供异常处理的本质是 seh 结构化异常处理, 通过修改 teb 数据结构来实现的,vc编译器是用__try __exception __finally语句来实现的,c++的话,看编译器怎么封装了,本质应该也离不开teb
说的当然是保护模式,保护模式下 int 3 就等同于引发一个异常 怎么捕获,就看你后面的代码怎么写了
xzdwfwt111 2009-01-04
  • 打赏
  • 举报
回复
不懂,顶
w_anthony 2009-01-04
  • 打赏
  • 举报
回复
To LS,首先我不是写Dos程序,其次我不是写驱动程序,所以肯定是保护模式下的代码,并且同样是保护模式,C++的try…catch捕获了int 3。

我反汇编过try…catch的,int 3指令执行后,直接跳转到catch代码,这个异常是可以捕获的,我现在就是希望用C语言实现这个效果。
zenny_chen 2009-01-04
  • 打赏
  • 举报
回复
如果你不在保护模式下的话应该会起作用。如果你在保护模式下发布int 3这条指令会因为访问特权指令而得到异常。

另外,C++的try-catch异常捕获是由编译器以纯软件的方式给出实现的,不通过使用硬件的中断。
呵呵,当然,你可以在DEBUG模式下进行尝试一些特权指令,不过这个模式是16位的实模式。在命令行输入DEBUG即可。
waizqfor 2009-01-04
  • 打赏
  • 举报
回复
没拿C写过抛异常的程序 不过你说的暴力手段很实来
xiaoyisnail 2009-01-04
  • 打赏
  • 举报
回复
用汇编直接改写int 3的中断向量表?
ysuliu 2009-01-04
  • 打赏
  • 举报
回复
不会,帮顶了。。
hhyttppd 2009-01-04
  • 打赏
  • 举报
回复
异常处理应该是平台相关的吧?

69,371

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧