Archive for July, 2007
贴士吧
最近没事,搞了个‘贴士吧’用来记录自己的Tips,还未完工。
为什么不用SEH
前些时候,在论坛上看到一个朋友说SEH怎么怎么不好,一定不要用它。其实存在即合理。就像GOTO,不能因为它破坏了程序的流程,就不用它,适当的使用,还是可以事半功倍的。
大家知道SEH是Windows操作系统提供的一种异常处理机制,它和C++无关。在Compiler编译的时候,就把这个机制加入了我们的程序中。在VC下可以用__try, __finally, __except, __leave等关键字来标识。由于SEH可以捕获硬件异常(Hardware Exception)和软件异常(Software Exception),它比C++的异常机制能捕获更多的异常,所以有朋友不喜欢这点,认为它掩盖了错误。其实这种说法是也是合情合理的,毕竟掩盖错误不是最好的解决方案,找出问题的所在才是我们应该做的。可是在现实中,我们不可能找到所有的bug,或者由于时间的关系,来不及修补这个bug,不如先用SEH挡一挡,何尝不可。
就像我之前的一个项目,程序在一个地方偶尔会Crash掉,而且这个地方如果不能正常执行丝毫不影响整个程序的运作,不会对用户造成损失,在找出问题真正的原因之前,我们完全可以用SEH捕获异常。
下面的例子也是一个SEH优势的体现
BOOL SafeDiv(INT32 dividend, INT32 divisor, INT32 *pResult)
{
__try
{
*pResult = dividend / divisor;
}
__except(GetExceptionCode() == EXCEPTION_INT_DIVIDE_BY_ZERO ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
{
return FALSE;
}
return TRUE;
}
SafeDiv用来做除法操作,它的返回值指出函数是否执行成功。pResult指向最终的结果,如果不用SEH,这类Hardware Exception会导致程序Crash,这里引入了SEH,我们在发现有除零错误的时候,让函数返回FALSE,调用处通过检查函数的返回值就可以判断除法运算是否成功,没必要就因为一个除零错误导致程序Crash掉。
由于SEH是Windows操作系统特有的机制,所以它不适合用在那些跨平台的代码,这种情况不用也罢,既然SEH是一个Windows的一个很好的异常处理机制,我们虽不能滥用它,适当的、合理的使用还是值得推荐的。
P.S.
For details about SEH, check this: http://www.google.com/search?hl=en&q=Programming+Applications+for+Microsoft+Windows
API Hook的问题,卡住了:(
这两天研究如何在我自己的进程中,获取IE或者FireFox中的网页内容,也就是监视用户上网信息。需要通过API Hook的方式拦截IE(拦截FireFox也是一个道理)用的API。
刚开始的思路是,我想Hook MSHTML.dll 中的API,用Depends看了一下,发现只有寥寥几个导出函数,诸如ShowHTMLDialog(), 这些都不能获取网页内容。那么再换个DLL呢,于是Depends一下,ShDocVw.dll,导出函数倒是不少,大部分名字都是N/A,只有几个如OpenURL(), AddUrlToFavorites(),对我也没什么用。
上面的方法不行,我只能再向底层靠了,准备Hook Ws2_32.dll,Depends这个DLL,你可以看到,N多导出函数,让人赏心悦目,其中recv就是我要Hook的API,写了一个Demo程序,然后打开IE,运行这个Demo,发现毫无反应,我开始怀疑是我的API Hook的方式不对,后来我用同样的方法,发现可以拦截住user32.dll的MessageBoxA,百思不得其解。Google一下,发现有人和我遇到类似的问题:
Hook MSN Messenger之socket通訊的鳥事
于是这次我挂到wsock32.dll,果然,这次有反应了。总算前进了一小步,离我要获得网页内容还有很多距离呢,我的recv函数中也就是my_recv内容如下:
int PASCAL FAR my_recv (SOCKET s, char FAR * buf, int len, int flags)
{
OutputDebugString(_T("In my_recv"));
OutputDebugString(buf);
SaveLog(buf, len);
int nReturn = 0;
myJmp.SetHookOff();
nReturn = recv(s, buf, len, flags);
myJmp.SetHookOn();
return (nReturn);
}
打印出buf的内容,用DebugView可以看到,很多都是乱码。不知道别人都怎么分析recv到的数据流的,怎么才能从中获取文本内容。接下来,保存也是一个问题,SaveLog的第二个参数是buf的长度,我觉得应该填recv的返回值,它是实际返回的数据的长度。但是把SaveLog放到recv后面,就不能保存到文件中,放到前面就可以,没办法,这里我只能用len。
打开文件如下图:
最后还有个问题是:卸载这个钩子的时候,偶尔会让IE崩溃。下面是我的一个demo,有兴趣的可以帮忙调试看看上面的若干个问题该怎么解决。写的仓促,代码很乱,我也没去测试Release是否有问题,暂且这么着吧。