具体表现是,在程序最开始处Hook上RegQueryValueExW,在整个程序运行的过程中,只有一部分调用进行了我自己实现的方法中,而有一部分调用却没有进入。
前前后后猜了很多原因,一开始以为是调用了SHQueryValueEx、RegEnumRegQueryMultipleValues等其他方法,但是使用ApiMonitor却发现调用确实是发生在RegQueryValueExW,但是调用返回的数据却是空。这就奇怪了,因为从程序执行结果上来看,明明是获取到了正确的值。
当时找到合理的解决方案,于是使用了一个临时的也是最土的方案,在模块初始化前RegSetValue保存并修改注册表的值,在模块初始化完成以后,再恢复回原来的注册表值。由于修改的是IE的相关键值,因为被360等各种报。
昨天又用ApiMonitor尝试了一下,突然发现,原来注册表相关函数,竟然在Advapi32.DLL和Kernel32.dll两个系统模块里存在两套实现,如下图:
图1 注册表函数有两套实现
图1中分别显示了对Kernel32(上半部分)和对Advapi32(下半部分)中RegQueryValueExW函数的调用 。
程序里默认使用Detours对函数进行Hook的代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
|
// 函数真实地址
LONG
(
WINAPI
*
PfnRegQueryValueExW
)
(
HKEY
hKey
,
LPCWSTR
lpValueName
,
LPDWORD
lpReserved
,
LPDWORD
lpType
,
LPBYTE
lpData
,
LPDWORD
lpcbData
)
=
&
::
RegQueryValueExW
;
// Hook该方法
DetourAttach
(
&
(
PVOID
&
)
PfnRegQueryValueExW
,
HookRegQueryValueExW
)
;
// Hook函数实现
LONG
WINAPI
HookRegQueryValueExW
(
HKEY
hKey
,
LPCWSTR
lpValueName
,
LPDWORD
lpReserved
,
LPDWORD
lpType
,
LPBYTE
lpData
,
LPDWORD
lpcbData
)
{
LONG
lResult
=
PfnRegQueryValueExW
(
hKey
,
lpValueName
,
lpReserved
,
lpType
,
lpData
,
lpcbData
)
;
return
lResult
;
}
|
在VS里调试时打开反汇编(Alt+8),单步跟踪,可以看到这样写的结果是,HookRegQueryValueExW函数里调用的其实是位于Advapi32里的_RegQueryValueExWStub@24方法,而该方法内部实现则是调用了Kernel32中的RegQueryValueExW方法。
到此问题原因找到了,只要让上述代码能Hook到Kernel32中函数即可。方法如下:
|
PfnRegQueryValueExW
=
(
LONG
(
__stdcall *
)
(
HKEY
,
LPCWSTR
,
LPDWORD
,
LPDWORD
,
LPBYTE
,
LPDWORD
)
)
GetProcAddress
(
GetModuleHandle
(
L
"Kernel32.dll"
)
,
"RegQueryValueExW"
)
;
DetourAttach
(
&
(
PVOID
&
)
PfnRegQueryValueExW
,
HookRegQueryValueExW
)
;
PfnRegQueryValueExW
=
(
LONG
(
__stdcall *
)
(
HKEY
,
LPCWSTR
,
LPDWORD
,
LPDWORD
,
LPBYTE
,
LPDWORD
)
)
GetProcAddress
(
GetModuleHandle
(
L
"advapi32.dll"
)
,
"RegQueryValueExW"
)
;
DetourAttach
(
&
(
PVOID
&
)
PfnRegQueryValueExW
,
HookRegQueryValueExW
)
;
|
刚查证了下MSDN,MSDN里写的竟然只有Advapi32,还是实践出真知啊。