前两天有朋友问:“如何监控自己的程序创建的子进程所发生的异常?”一开始,我以为这子进程是他自己编写的程序,所以直接就说:“在子进程的代码中使用“SetUnhandledExceptionFilter”这个API,注册一个未处理异常的回调函数,然后在回调函数中做相应处理就可以了。”实际上,现在大部分应用程序也都使用了这个API来监控自己的程序的崩溃情况。例如QQ、遨游等,在崩溃的时候都会提示需要发送一个错误报告文件,这个错误报告文件就是用这种方式生成的。
但是,随后这位朋友说,这个子进程并不是他编写的,没办法修改程序的代码。实际上他是需要做计算机病毒分析,要对一些病毒程序的运行情况进行监控。
在这样的状况下,我想到了这样一个思路:就是将他的监控程序注册为系统中的实时调试器,这样系统中有任何进程发生崩溃时,Windows都会将该进程的PID传递给这个监控程序。至于崩溃进程是否是他的子进程,只需要根据PID就可以简单地判断出来了。
所谓“实时调试”(英语叫Just-In-Time debugging),其实就是Visual Studio以及Windbg等调试程序将自己注册为系统中的默认调试器的机制。用过Visual Studio的都知道,安装了这玩意之后,每当程序崩溃,VS都可以直接跳出来询问是否对该进程进行调试,这就是“实时调试”的能力。
具体的注册方式其实很简单,修改注册表就可以实现。打开[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug]这个键,在其下建立“Debugger”的字符串值,具体内容填写“监控进程的全路径 -p %ld -e %ld”,例如“c:\exceptionMonitor.exe -p %ld -e %ld”。监控程序要支持两个参数,一个是“-p”,一个是“-e”,当有程序崩溃时,系统会把用程序的PID替换参数中的“%ld”,传递给监控程序。
但还有一些其他的问题,这就是系统只能设置一个实时调试器。如果系统中已经有VS等程序注册过了,我们去修改这个值不就影响了这些程序的监控吗?这个问题其实也好解决,只要采取计算机安全领域里用到烂大街的“Hook”思想就可以了。具体方式是首先将VS等其他程序注册的“Debugger”值保存到另外一个键值下,例如取名为“PreviousDebugger”,然后再把我们的程序写到真正的“Debugger”键值下。当系统中的程序发生崩溃并被我们的监控程序截获后,我们首先进行自己的处理,处理完毕再根据“PreviousDebugger”中记录的调试程序路径,将崩溃的程序“扔”给后续的调试程序。如此一来,大家都有机会进行处理,各取所需,皆大欢喜了。
最后要说明的是,在[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug]下面还有一个Auto值,如果这个值为“0”的话,那么当程序崩溃的时候系统会弹出一个对话框,让用户选择是否启动调试器。要是用户选择不启动,我们的监控程序就等于是“白给”了。所以,我们务必要把这个值设为“1”啊,切记切记。
转自:
http://blog.sina.com.cn/s/blog_53f909390100n3p8.html