advapi32.dll kernel32.dll 中的两套注册表API

日前遇到一件事:WebBrowser中的网页会用到一个“大众”ActiveX控件,为了保证兼容性以及和其它程序互不干扰,我们采用这样一种方案:
1. 我们的软件会自带该控件;
2. 如果系统中已注册有该控件的话,我们不用会我们的控件进行覆盖注册;
3. 不管怎么样,我们的程序都只会加载我们自带的控件。
 
要做到第3条,显然要HOOK控件位置有关的注册表项。因为之前在做播放器时使用过同样的手段来处理媒体解码器,所以其实并没有什么难度。但事实上却差点阴沟里翻船。
 
我一定确定以及肯定的是,我需要HOOK的只有几个API:RegQueryValue、RegQueryValueEx、RegGetValue。用ZwQueryKey还原一下路径,如果路径是"CLSID\{GUID}\InprocServer32",把我们自带控件的路径返回即可。
 
然而,程序实际运行却并没有预期效果,程序虽然执行到了API的替代函数中,但是结果却要么加载到其它版本的控件,要么加载失败。
 
修正了数遍代码,把捕获条件放宽收窄N次,尝试HOOK其它一些API之后,换了N台机器,检查了N遍注册表后,问题依旧。
 
跟踪了无数遍,程序始终会执行到API的替代函数中,也返回了正确结果。但是在procemon的监测里,却又始终能看到返回注册表中真实值的注册表读取操作。
我花了一些时间后,意识到:在API替代品中就已经被我处理掉的请求,应该是不会进入到Procemon纪录中的。也就是说,procemon中监控到的请求,跟被我HOOK到的请求,其实是来自完全不同的调用路径。但是查看procemon纪录中这些操作的调用堆栈,无一不是来自已经被我HOOK了的API。
 
这说明了一个更加难以解释的问题:同样的API,同样的参数(路径),为什么有些能够HOOK到,有些则HOOK不到?
 
为此又回过头去检查和修正捕获操作的代码,但毫无收获。
 
最后告诉我答案的来自美工使用旧版本程序的一个错误报告:XP系统下提示Advapi32.dll找不到某注册表API。我突然想起,procemon纪录中的调用堆栈中的API,似乎并不是Advapi32.dll模块的,而是Kernel32.dll。马上查询了一下,确认程序链接的都是Advapi32.dll,而procemon中监控到的,也确认属于Kernel32.dll。
 
答案呼之欲出,用depends看了一下Lernel32.dll,果然如此,一模一样的API,一个不少!!!也就是说,我HOOK了advapi32.dll的API,但程序却明修栈道,暗渡陈仓,调用了一两次advapi32.dll中的API,最后却从Kernel32.dll绕道去拿了数据。
 
虽然问题找到了,但是依然还是不太明白。以前HOOK注册表并没有出现过类似问题,显然,那些程序里注册表调用都走的是Advapi32.dll,MSDN中所有的注册表API也都注明在Advapi32.dll里,那为什么这一次却到了Kernel32.dll,唯一能想到的解释,或许这IE内核有关。但这一点就无力求证了。
 
最后,虽然没有文档告诉我Kernel32.dll中注册表函数的原型,但尝试用Advapi32.dll中的原型HOOK了一下,程序正常。可见是一个牌子,两套班子。
 
Tip:RegGetValue要求Vista以上或XP64bit。
posted @ 2014-03-29 22:46  泉子  阅读(1569)  评论(0编辑  收藏  举报