消息钩子在Windows编程中有着非常广泛的应用,它可以任意拦截Windows系统,这个以消息为驱动的系统中的绝大多数消息类型。一方面这给编程者带来了巨大的灵活性,另一方面也埋下了巨大隐患,大多数窃密软件都使用这种方法。此篇文章给您提供一种钩子的反拦截方法,希望对您有所帮助。文章中使用了API钩子,您之前必须对此技术有一定了解。
为求完整,文章分为两部分,第一部分为消息钩子的使用,熟悉此技术的读者可以直接跳过此节。第二部分为消息钩子的反拦截。
一、消息钩子的使用。
消息钩子分为本地(local)和远程(remote)两种(两个local system-wide hook例外,无关主题,不多说了)。local类型的钩子函数只能拦截本进程的消息。能够拦截本进程以外的消息的钩子,都是remote类型。remote类型的钩子必须放在DLL里面。下面以remote类型为例,通过安装键盘钩子介绍其使用。
1、首先建立DLL,在头文件中添加如下代码。
#ifdef KM_EXPORTS
#define KM_API __declspec(dllexport)
#else
#define KM_API __declspec(dllimport)
#endif
KM_API BOOL HookStart();//安装钩子
KM_API BOOL HookStop();//卸载钩子
2、在.cpp文件中添加代码
#pragma data_seg("Shared")
HHOOK g_hhookKey=NULL;
#pragma data_seg()
#pragma comment(linker,"/SECTION:Shared,RWS")
g_hhookKey为键盘钩子的句柄,为确保此数值在所有实例中均保持不变,将其存放于此模块所有实例的共享数据区,若在exe程序中按此格式添加一int 变量 appNum,在程序启动时appNum++,则可以通过访问此变量的数值,确定有多少个exe的实例,当然这种方法也可以替代同步对象用于只启动一个实例。
HINSTANCE g_hinstDll=NULL; //添加全局变量用于记录此DLL模块的句柄
BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved )
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
g_hinstDll=(HINSTANCE)hModule;//在DLL加载时对全局变量赋值
..................
}
}
LRESULT KeyHookProc(int nCode,WPARAM wParam,LPARAM lParam)//键盘钩子的过滤函数
{
.....................
return::CallNextHookEx(g_hhookKey,nCode,wParam,lParam);//*****请留意此行代码*****
}
BOOL HookStart()//安装钩子
{
g_hhookKey=::SetWindowsHookEx(WH_KEYBOARD,(HOOKPROC)KeyHookProc,g_hinstDll,
::GetWindowThreadProcessId(::FindWindow(NULL,"被监视的窗口的标题"),NULL) );
return (g_hhookKey!=NULL);
}
BOOL HookStop()//卸载钩子
{
BOOL ret;
if(g_hhookKey!=NULL)
ret=::UnhookWindowsHookEx(g_hhookKey);
g_hhookKey=NULL;
return ret;
}
只要在exe程序中调用HookStart函数,就可以监视某一窗口的键盘消息,若此窗口为QQ的密码框,你的密码就泄漏了。
二、消息钩子的反拦截。
请留意前面带*号注释的代码,其中传入了钩子的句柄g_hhookKey,只要使用API钩子将CallNextHookEx函数替换,并在替换函数中将其卸载,消息钩子就完蛋了。同时,还要保证本进程安装的钩子不被卸载,其中既可能有local类型的还可能有remote类型的。不要以为自己没有在程序中安装钩子,程序中就一定没有安装钩子,在MFC4版本中,MFC会自己装一个local类型的钩子,MFC7版本中好像没了。好了,下面介绍其实现。
1、建立DLL,在头文件中添加如下代码。
#ifdef HOOKFORBID_EXPORTS
#define HOOKFORBID_API __declspec(dllexport)
#else
#define HOOKFORBID_API __declspec(dllimport)
#endif
HOOKFORBID_API int fnHookForbid(void);//在exe程序中调用此函数,使DLL加载
HOOKFORBID_API bool AddHhook(HHOOK Hhook);//若exe中安装remote类型消息钩子,将其句柄添加
HOOKFORBID_API bool DelHhook(HHOOK Hhook);//在exe中卸载remote类型消息钩子时,删除其句柄
2、在.cpp文件中添加代码。
CArray<HHOOK,HHOOK> array;//用于记录本进程安装的钩子的句柄
//////////////////////////////////////////////////////////////////////////////
int fnHookForbid(void)
{
return 1;
}
bool AddHhook(HHOOK Hhook)
{
array.Add(Hhook);
return true;
}
bool DelHhook(HHOOK Hhook)
{
bool ret=false;
for(int i=0;i<array.GetSize();i++)
{
if(array.GetAt(i)==Hhook)
{
array.RemoveAt(i);
ret=true;
break;
}
}
return ret;
}
//////////////////////////////////////////////////////////////////////////////
下面的代码用于API替换,其中用到了CAPIHook 类,《Windows 核心编程》(Jeffrey Richter著)一书中有源代码。使用其它开发包也可以实现此功能。
//////////////////////////////////////////////////////////////////////////////
typedef HHOOK (WINAPI *PFNSETWINDOWSHOOKEX)(
int idHook,
HOOKPROC lpfn,
HINSTANCE hMod,
DWORD dwThreadId
);
typedef LRESULT (WINAPI *PFNCALLNEXTHOOKEX)(
HHOOK hhk,
int nCode,
WPARAM wParam,
LPARAM lParam
);
//////////////////////////////////////////////////////////////////////////////
extern CAPIHook g_SetWindowsHookExA;
extern CAPIHook g_SetWindowsHookExW;
extern CAPIHook g_CallNextHookEx;
//////////////////////////////////////////////////////////////////////////////
//此函数用于替换SetWindowsHookEx函数的ASCII版本SetWindowsHookExA
HHOOK WINAPI Hook_SetWindowsHookExA( int idHook, HOOKPROC lpfn, HINSTANCE hMod, DWORD dwThreadId )
{
HHOOK nResult =0;
nResult = ((PFNSETWINDOWSHOOKEX)(PROC) g_SetWindowsHookExA)( idHook, lpfn, hMod, dwThreadId );
//若在本进程中安装了local类型钩子,记录其句柄
if(hMod==NULL)
array.Add(nResult);
return(nResult);
}
//此函数用于替换SetWindowsHookEx函数的UNICODE版本SetWindowsHookExW
HHOOK WINAPI Hook_SetWindowsHookExW( int idHook, HOOKPROC lpfn, HINSTANCE hMod, DWORD dwThreadId )
{
HHOOK nResult =0;
nResult = ((PFNSETWINDOWSHOOKEX)(PROC) g_SetWindowsHookExW)( idHook, lpfn, hMod, dwThreadId );
//若在本进程中安装了local类型钩子,记录其句柄
if(hMod==NULL)
array.Add(nResult);
return(nResult);
}
//此函数用于替换CallNextHookEx函数,此函数只有一个版本
LRESULT WINAPI Hook_CallNextHookEx( HHOOK hhk, int nCode, WPARAM wParam, LPARAM lParam)
{
LRESULT nResult =0;
nResult = ((PFNCALLNEXTHOOKEX)(PROC) g_CallNextHookEx)( hhk, nCode, wParam, lParam );
//在数组中查找句柄,若找不到,将其卸载
bool bfind=false;
for(int i=0;i<array.GetSize();i++)
{
if(array.GetAt(i)==hhk)
{
bfind=true;
break;
}
}
if(!bfind)
{
UnhookWindowsHookEx( hhk );
}
return (nResult);
}
//////////////////////////////////////////////////////////////////////////////
//使用CAPIHook 类对函数进行替换
CAPIHook g_SetWindowsHookExA("User32.dll", "SetWindowsHookExA",
(PROC) Hook_SetWindowsHookExA, true);
CAPIHook g_SetWindowsHookExW("User32.dll", "SetWindowsHookExW",
(PROC) Hook_SetWindowsHookExW, true);
CAPIHook g_CallNextHookEx("User32.dll", "CallNextHookEx",
(PROC) Hook_CallNextHookEx, true);
到了这里,所有工作都完成了,只要在exe程序中调用fnHookForbid函数,并在安装remote类型钩子时调用AddHhook函数记录其句柄,卸载时调用DelHhook函数删除句柄就万事ok了。
一点不足:这种方法可以有效屏蔽消息钩子对信息安全的威胁。可以使Spy++失效。然而,由于是在CallNextHookEx函数中卸载钩子,因此,钩子函数总是会被调用一次。还有一件非常费解的事,金山词霸总能够正常取词,不知道词霸是怎么做到的。
本人并非专业程序员, 若此方法存在任何错误或隐患,敬请批评指出,请不要在帖子上损我。
97 个解决方案
#1
好贴。 mark
#2
好贴,学习
#3
不错,顶
#4
好文章,先收藏,再慢慢看
#5
收藏了
#6
收藏
#7
收藏
#8
将函数Hook_CallNextHookEx
//此函数用于替换CallNextHookEx函数,此函数只有一个版本
LRESULT WINAPI Hook_CallNextHookEx( HHOOK hhk, int nCode, WPARAM wParam, LPARAM lParam)
{
LRESULT nResult =0;
//在数组中查找句柄,若找不到,将其卸载
bool bfind=false;
for(int i=0;i<array.GetSize();i++)
{
if(array.GetAt(i)==hhk)
{
bfind=true;
break;
}
}
if(!bfind)
{
UnhookWindowsHookEx( hhk );
nResult = 0;
}
else
nResult = ((PFNCALLNEXTHOOKEX)(PROC) g_CallNextHookEx)( hhk, nCode, wParam, lParam );
//此处是从上面移下来的,也就是说如果不是local hook就不真正执行
//不知是否可以解决你说的“钩子函数总是会被调用一次”的问题
return (nResult);
}
//此函数用于替换CallNextHookEx函数,此函数只有一个版本
LRESULT WINAPI Hook_CallNextHookEx( HHOOK hhk, int nCode, WPARAM wParam, LPARAM lParam)
{
LRESULT nResult =0;
//在数组中查找句柄,若找不到,将其卸载
bool bfind=false;
for(int i=0;i<array.GetSize();i++)
{
if(array.GetAt(i)==hhk)
{
bfind=true;
break;
}
}
if(!bfind)
{
UnhookWindowsHookEx( hhk );
nResult = 0;
}
else
nResult = ((PFNCALLNEXTHOOKEX)(PROC) g_CallNextHookEx)( hhk, nCode, wParam, lParam );
//此处是从上面移下来的,也就是说如果不是local hook就不真正执行
//不知是否可以解决你说的“钩子函数总是会被调用一次”的问题
return (nResult);
}
#9
Mark,then read.
#10
厉害
#11
支持
#12
DeadWolf(三角小眼睛又邪又媚又笨又呆又奸又诈又色)
LRESULT KeyHookProc(int nCode,WPARAM wParam,LPARAM lParam)//键盘钩子的过滤函数
{
.....................//执行代码
return::CallNextHookEx(g_hhookKey,nCode,wParam,lParam);//*****请留意此行代码*****
}
函数CallNextHookEx被替换,钩子在替换函数中被卸载,无论如何在替换函数中处理代码,键盘钩子的过滤函数已经将执行代码执行了一次。
LRESULT KeyHookProc(int nCode,WPARAM wParam,LPARAM lParam)//键盘钩子的过滤函数
{
.....................//执行代码
return::CallNextHookEx(g_hhookKey,nCode,wParam,lParam);//*****请留意此行代码*****
}
函数CallNextHookEx被替换,钩子在替换函数中被卸载,无论如何在替换函数中处理代码,键盘钩子的过滤函数已经将执行代码执行了一次。
#13
好贴,真不错~~~
#14
呵呵!假如我的钩子是这么用的:
FUN_SETWINDOWSHOOKA *pFn = (FUN_SETWINDOWSHOOKA *)
::GetProcAddress(::GetModuleHandle("kernel32.dll"), "SetWindowsHookA");
pFn(...);
你的方法还是屏蔽不了哦!不信试验一下!记得给分哦!(该法为:“反反API钩子大法”)
FUN_SETWINDOWSHOOKA *pFn = (FUN_SETWINDOWSHOOKA *)
::GetProcAddress(::GetModuleHandle("kernel32.dll"), "SetWindowsHookA");
pFn(...);
你的方法还是屏蔽不了哦!不信试验一下!记得给分哦!(该法为:“反反API钩子大法”)
#15
当然!同理也可以绕过API钩子!有同样兴趣的人记得发消息给我哦!
#16
Rogeremail(绿色环保-菜青虫)
呵呵!假如我的钩子是这么用的:
FUN_SETWINDOWSHOOKA *pFn = (FUN_SETWINDOWSHOOKA *)
::GetProcAddress(::GetModuleHandle("kernel32.dll"), "SetWindowsHookA");
pFn(...);
你的方法还是屏蔽不了哦!不信试验一下!记得给分哦!(该法为:“反反API钩子大法”)
当然!同理也可以绕过API钩子!有同样兴趣的人记得发消息给我哦!
首先声明一下:我拦截的是消息钩子,如果安装钩子时考虑到了反卸载则不在讨论之内。
其次:上述方法不可靠,对CAPIHook类进行更改,可以实时对地址进行替换,就象消息钩子被调用次序的不确定性一样,到时候没法确定那个替换函数被调用了。
呵呵!假如我的钩子是这么用的:
FUN_SETWINDOWSHOOKA *pFn = (FUN_SETWINDOWSHOOKA *)
::GetProcAddress(::GetModuleHandle("kernel32.dll"), "SetWindowsHookA");
pFn(...);
你的方法还是屏蔽不了哦!不信试验一下!记得给分哦!(该法为:“反反API钩子大法”)
当然!同理也可以绕过API钩子!有同样兴趣的人记得发消息给我哦!
首先声明一下:我拦截的是消息钩子,如果安装钩子时考虑到了反卸载则不在讨论之内。
其次:上述方法不可靠,对CAPIHook类进行更改,可以实时对地址进行替换,就象消息钩子被调用次序的不确定性一样,到时候没法确定那个替换函数被调用了。
#17
转贴
防止全局钩子的侵入
Author: pjf(jfpan20000@sina.com)
Windows消息钩子一般都很熟悉了。它的用处很多,耳熟能详的就有——利用键盘钩子获取目标进程的键盘输入,从而获得各类密码以达到不可告人的目的。朋友想让他的软件不被别人的全局钩子监视,有没有办法实现呢?答案是肯定的,不过缺陷也是有的。
首先简单看看全局钩子如何注入别的进程。
消息钩子是由Win32子系统提供,其核心部分通过NtUserSetWindowsHookEx为用户提供了设置消息钩子的系统服务,用户通过它注册全局钩子。当系统获取某些事件,比如用户按键,键盘driver将扫描码等传入win32k的KeyEvent处理函数,处理函数判断有无相应hook,有则callhook。此时,系统取得Hook对象信息,若目标进程没有装载对应的Dll,则装载之(利用KeUserModeCallback“调用”用户例程,它与Apc调用不同,它是仿制中断返回环境,其调用是“立即”性质的)。
进入用户态的KiUserCallbackDispatcher后,KiUserCallbackDispatcher根据传递的数据获取所需调用的函数、参数等,随后调用。针对上面的例子,为装载hook dll,得到调用的是LoadLibraryExW,随后进入LdrLoadDll,装载完毕后返回,后面的步骤就不叙述了。
从上面的讨论我们可以得出一个最简单的防侵入方案:在加载hook dll之前hook相应api使得加载失败,不过有一个缺陷:系统并不会因为一次的失败而放弃,每次有消息产生欲call hook时系统都会试图在你的进程加载dll,这对于性能有些微影响,不过应该感觉不到。剩下一个问题就是不是所有的LoadLibraryExW都应拦截,这个容易解决,比如判断返回地址。下面给出一个例子片断,可以添加一些判断使得某些允许加载的hook dll被加载。
这里hook api使用了微软的detours库,可自行修改。
以下内容为程序代码:
typedef HMODULE (__stdcall *LOADLIB)(
LPCWSTR lpwLibFileName,
HANDLE hFile,
DWORD dwFlags);
extern "C" {
DETOUR_TRAMPOLINE(HMODULE __stdcall Real_LoadLibraryExW(
LPCWSTR lpwLibFileName,
HANDLE hFile,
DWORD dwFlags),
LoadLibraryExW);
}
ULONG user32 = 0;
HMODULE __stdcall Mine_LoadLibraryExW(
LPCWSTR lpwLibFileName,
HANDLE hFile,
DWORD dwFlags)
{
ULONG addr;
_asm mov eax, [ebp+4]
_asm mov addr, eax
if ((user32 & 0xFFFF0000) == (addr & 0xFFFF0000))
{
return 0;
}
HMODULE res = (LOADLIB(Real_LoadLibraryExW)) (
lpwLibFileName,
hFile,
dwFlags);
return res;
}
BOOL ProcessAttach()
{
DetourFunctionWithTrampoline((PBYTE)Real_LoadLibraryExW,
(PBYTE)Mine_LoadLibraryExW);
return TRUE;
}
BOOL ProcessDetach()
{
DetourRemove((PBYTE)Real_LoadLibraryExW,
(PBYTE)Mine_LoadLibraryExW);
return TRUE;
}
CAnti_HookApp::CAnti_HookApp() //在使用用户界面服务前调用ProcessAttach
{
user32 = (ULONG)GetModuleHandle("User32.dll");
ProcessAttach();
}
防止全局钩子的侵入
Author: pjf(jfpan20000@sina.com)
Windows消息钩子一般都很熟悉了。它的用处很多,耳熟能详的就有——利用键盘钩子获取目标进程的键盘输入,从而获得各类密码以达到不可告人的目的。朋友想让他的软件不被别人的全局钩子监视,有没有办法实现呢?答案是肯定的,不过缺陷也是有的。
首先简单看看全局钩子如何注入别的进程。
消息钩子是由Win32子系统提供,其核心部分通过NtUserSetWindowsHookEx为用户提供了设置消息钩子的系统服务,用户通过它注册全局钩子。当系统获取某些事件,比如用户按键,键盘driver将扫描码等传入win32k的KeyEvent处理函数,处理函数判断有无相应hook,有则callhook。此时,系统取得Hook对象信息,若目标进程没有装载对应的Dll,则装载之(利用KeUserModeCallback“调用”用户例程,它与Apc调用不同,它是仿制中断返回环境,其调用是“立即”性质的)。
进入用户态的KiUserCallbackDispatcher后,KiUserCallbackDispatcher根据传递的数据获取所需调用的函数、参数等,随后调用。针对上面的例子,为装载hook dll,得到调用的是LoadLibraryExW,随后进入LdrLoadDll,装载完毕后返回,后面的步骤就不叙述了。
从上面的讨论我们可以得出一个最简单的防侵入方案:在加载hook dll之前hook相应api使得加载失败,不过有一个缺陷:系统并不会因为一次的失败而放弃,每次有消息产生欲call hook时系统都会试图在你的进程加载dll,这对于性能有些微影响,不过应该感觉不到。剩下一个问题就是不是所有的LoadLibraryExW都应拦截,这个容易解决,比如判断返回地址。下面给出一个例子片断,可以添加一些判断使得某些允许加载的hook dll被加载。
这里hook api使用了微软的detours库,可自行修改。
以下内容为程序代码:
typedef HMODULE (__stdcall *LOADLIB)(
LPCWSTR lpwLibFileName,
HANDLE hFile,
DWORD dwFlags);
extern "C" {
DETOUR_TRAMPOLINE(HMODULE __stdcall Real_LoadLibraryExW(
LPCWSTR lpwLibFileName,
HANDLE hFile,
DWORD dwFlags),
LoadLibraryExW);
}
ULONG user32 = 0;
HMODULE __stdcall Mine_LoadLibraryExW(
LPCWSTR lpwLibFileName,
HANDLE hFile,
DWORD dwFlags)
{
ULONG addr;
_asm mov eax, [ebp+4]
_asm mov addr, eax
if ((user32 & 0xFFFF0000) == (addr & 0xFFFF0000))
{
return 0;
}
HMODULE res = (LOADLIB(Real_LoadLibraryExW)) (
lpwLibFileName,
hFile,
dwFlags);
return res;
}
BOOL ProcessAttach()
{
DetourFunctionWithTrampoline((PBYTE)Real_LoadLibraryExW,
(PBYTE)Mine_LoadLibraryExW);
return TRUE;
}
BOOL ProcessDetach()
{
DetourRemove((PBYTE)Real_LoadLibraryExW,
(PBYTE)Mine_LoadLibraryExW);
return TRUE;
}
CAnti_HookApp::CAnti_HookApp() //在使用用户界面服务前调用ProcessAttach
{
user32 = (ULONG)GetModuleHandle("User32.dll");
ProcessAttach();
}
#18
to yafizyh(亚斐):
不好意思,我跑题了……
不好意思,我跑题了……
#19
多谢楼主分享
#20
up,mark,concern
#21
WINDOWS核心编程里的用IAT的APIHOOK是不全面的。
::GetProcAddress(::GetModuleHandle("kernel32.dll"), "SetWindowsHookA");
就可以绕过。
APIHOOK最好的方法还是直接修改API入口点的代码。
大家可以参考HXDEF(黑客守卫者)的原代码
::GetProcAddress(::GetModuleHandle("kernel32.dll"), "SetWindowsHookA");
就可以绕过。
APIHOOK最好的方法还是直接修改API入口点的代码。
大家可以参考HXDEF(黑客守卫者)的原代码
#22
mark
#23
up
#24
mark
#25
mark
#26
mark
#27
gz
#28
Very good!
mark
mark
#29
我现在也在用HOOK.
#30
严重收藏................................
#31
mark
#32
=======================
WINDOWS核心编程里的用IAT的APIHOOK是不全面的。
::GetProcAddress(::GetModuleHandle("kernel32.dll"), "SetWindowsHookA");
就可以绕过。
APIHOOK最好的方法还是直接修改API入口点的代码。
大家可以参考HXDEF(黑客守卫者)的原代码
=======================
同时HOOK GetProcAddress 不就行了,但是要是对方使用搜索PE函数导出表的话就没用了
WINDOWS核心编程里的用IAT的APIHOOK是不全面的。
::GetProcAddress(::GetModuleHandle("kernel32.dll"), "SetWindowsHookA");
就可以绕过。
APIHOOK最好的方法还是直接修改API入口点的代码。
大家可以参考HXDEF(黑客守卫者)的原代码
=======================
同时HOOK GetProcAddress 不就行了,但是要是对方使用搜索PE函数导出表的话就没用了
#33
一伙强人在比拼,我MARK一下。慢慢看。
#34
好贴~~~ mark
#35
好贴~~~ mark
#36
好 文章 顶 顶 顶
#37
mark
#38
mark
#39
呵呵,到此一游~签名!
#40
好贴~~~
我喜欢。
我喜欢。
#41
楼主说remote类型的钩子必须放在DLL里面,日志钩子也应属全局钩子吧。它是不需放DLL中的
#42
收藏!
#43
不错
#44
..
#45
MARK
#46
楼主说remote类型的钩子必须放在DLL里面,日志钩子也应属全局钩子吧。它是不需放DLL中的
两个local system-wide hook例外,无关主题
两个local system-wide hook例外,无关主题
#47
mark
#48
mark
#49
NB
#50
mark
#1
好贴。 mark
#2
好贴,学习
#3
不错,顶
#4
好文章,先收藏,再慢慢看
#5
收藏了
#6
收藏
#7
收藏
#8
将函数Hook_CallNextHookEx
//此函数用于替换CallNextHookEx函数,此函数只有一个版本
LRESULT WINAPI Hook_CallNextHookEx( HHOOK hhk, int nCode, WPARAM wParam, LPARAM lParam)
{
LRESULT nResult =0;
//在数组中查找句柄,若找不到,将其卸载
bool bfind=false;
for(int i=0;i<array.GetSize();i++)
{
if(array.GetAt(i)==hhk)
{
bfind=true;
break;
}
}
if(!bfind)
{
UnhookWindowsHookEx( hhk );
nResult = 0;
}
else
nResult = ((PFNCALLNEXTHOOKEX)(PROC) g_CallNextHookEx)( hhk, nCode, wParam, lParam );
//此处是从上面移下来的,也就是说如果不是local hook就不真正执行
//不知是否可以解决你说的“钩子函数总是会被调用一次”的问题
return (nResult);
}
//此函数用于替换CallNextHookEx函数,此函数只有一个版本
LRESULT WINAPI Hook_CallNextHookEx( HHOOK hhk, int nCode, WPARAM wParam, LPARAM lParam)
{
LRESULT nResult =0;
//在数组中查找句柄,若找不到,将其卸载
bool bfind=false;
for(int i=0;i<array.GetSize();i++)
{
if(array.GetAt(i)==hhk)
{
bfind=true;
break;
}
}
if(!bfind)
{
UnhookWindowsHookEx( hhk );
nResult = 0;
}
else
nResult = ((PFNCALLNEXTHOOKEX)(PROC) g_CallNextHookEx)( hhk, nCode, wParam, lParam );
//此处是从上面移下来的,也就是说如果不是local hook就不真正执行
//不知是否可以解决你说的“钩子函数总是会被调用一次”的问题
return (nResult);
}
#9
Mark,then read.
#10
厉害
#11
支持
#12
DeadWolf(三角小眼睛又邪又媚又笨又呆又奸又诈又色)
LRESULT KeyHookProc(int nCode,WPARAM wParam,LPARAM lParam)//键盘钩子的过滤函数
{
.....................//执行代码
return::CallNextHookEx(g_hhookKey,nCode,wParam,lParam);//*****请留意此行代码*****
}
函数CallNextHookEx被替换,钩子在替换函数中被卸载,无论如何在替换函数中处理代码,键盘钩子的过滤函数已经将执行代码执行了一次。
LRESULT KeyHookProc(int nCode,WPARAM wParam,LPARAM lParam)//键盘钩子的过滤函数
{
.....................//执行代码
return::CallNextHookEx(g_hhookKey,nCode,wParam,lParam);//*****请留意此行代码*****
}
函数CallNextHookEx被替换,钩子在替换函数中被卸载,无论如何在替换函数中处理代码,键盘钩子的过滤函数已经将执行代码执行了一次。
#13
好贴,真不错~~~
#14
呵呵!假如我的钩子是这么用的:
FUN_SETWINDOWSHOOKA *pFn = (FUN_SETWINDOWSHOOKA *)
::GetProcAddress(::GetModuleHandle("kernel32.dll"), "SetWindowsHookA");
pFn(...);
你的方法还是屏蔽不了哦!不信试验一下!记得给分哦!(该法为:“反反API钩子大法”)
FUN_SETWINDOWSHOOKA *pFn = (FUN_SETWINDOWSHOOKA *)
::GetProcAddress(::GetModuleHandle("kernel32.dll"), "SetWindowsHookA");
pFn(...);
你的方法还是屏蔽不了哦!不信试验一下!记得给分哦!(该法为:“反反API钩子大法”)
#15
当然!同理也可以绕过API钩子!有同样兴趣的人记得发消息给我哦!
#16
Rogeremail(绿色环保-菜青虫)
呵呵!假如我的钩子是这么用的:
FUN_SETWINDOWSHOOKA *pFn = (FUN_SETWINDOWSHOOKA *)
::GetProcAddress(::GetModuleHandle("kernel32.dll"), "SetWindowsHookA");
pFn(...);
你的方法还是屏蔽不了哦!不信试验一下!记得给分哦!(该法为:“反反API钩子大法”)
当然!同理也可以绕过API钩子!有同样兴趣的人记得发消息给我哦!
首先声明一下:我拦截的是消息钩子,如果安装钩子时考虑到了反卸载则不在讨论之内。
其次:上述方法不可靠,对CAPIHook类进行更改,可以实时对地址进行替换,就象消息钩子被调用次序的不确定性一样,到时候没法确定那个替换函数被调用了。
呵呵!假如我的钩子是这么用的:
FUN_SETWINDOWSHOOKA *pFn = (FUN_SETWINDOWSHOOKA *)
::GetProcAddress(::GetModuleHandle("kernel32.dll"), "SetWindowsHookA");
pFn(...);
你的方法还是屏蔽不了哦!不信试验一下!记得给分哦!(该法为:“反反API钩子大法”)
当然!同理也可以绕过API钩子!有同样兴趣的人记得发消息给我哦!
首先声明一下:我拦截的是消息钩子,如果安装钩子时考虑到了反卸载则不在讨论之内。
其次:上述方法不可靠,对CAPIHook类进行更改,可以实时对地址进行替换,就象消息钩子被调用次序的不确定性一样,到时候没法确定那个替换函数被调用了。
#17
转贴
防止全局钩子的侵入
Author: pjf(jfpan20000@sina.com)
Windows消息钩子一般都很熟悉了。它的用处很多,耳熟能详的就有——利用键盘钩子获取目标进程的键盘输入,从而获得各类密码以达到不可告人的目的。朋友想让他的软件不被别人的全局钩子监视,有没有办法实现呢?答案是肯定的,不过缺陷也是有的。
首先简单看看全局钩子如何注入别的进程。
消息钩子是由Win32子系统提供,其核心部分通过NtUserSetWindowsHookEx为用户提供了设置消息钩子的系统服务,用户通过它注册全局钩子。当系统获取某些事件,比如用户按键,键盘driver将扫描码等传入win32k的KeyEvent处理函数,处理函数判断有无相应hook,有则callhook。此时,系统取得Hook对象信息,若目标进程没有装载对应的Dll,则装载之(利用KeUserModeCallback“调用”用户例程,它与Apc调用不同,它是仿制中断返回环境,其调用是“立即”性质的)。
进入用户态的KiUserCallbackDispatcher后,KiUserCallbackDispatcher根据传递的数据获取所需调用的函数、参数等,随后调用。针对上面的例子,为装载hook dll,得到调用的是LoadLibraryExW,随后进入LdrLoadDll,装载完毕后返回,后面的步骤就不叙述了。
从上面的讨论我们可以得出一个最简单的防侵入方案:在加载hook dll之前hook相应api使得加载失败,不过有一个缺陷:系统并不会因为一次的失败而放弃,每次有消息产生欲call hook时系统都会试图在你的进程加载dll,这对于性能有些微影响,不过应该感觉不到。剩下一个问题就是不是所有的LoadLibraryExW都应拦截,这个容易解决,比如判断返回地址。下面给出一个例子片断,可以添加一些判断使得某些允许加载的hook dll被加载。
这里hook api使用了微软的detours库,可自行修改。
以下内容为程序代码:
typedef HMODULE (__stdcall *LOADLIB)(
LPCWSTR lpwLibFileName,
HANDLE hFile,
DWORD dwFlags);
extern "C" {
DETOUR_TRAMPOLINE(HMODULE __stdcall Real_LoadLibraryExW(
LPCWSTR lpwLibFileName,
HANDLE hFile,
DWORD dwFlags),
LoadLibraryExW);
}
ULONG user32 = 0;
HMODULE __stdcall Mine_LoadLibraryExW(
LPCWSTR lpwLibFileName,
HANDLE hFile,
DWORD dwFlags)
{
ULONG addr;
_asm mov eax, [ebp+4]
_asm mov addr, eax
if ((user32 & 0xFFFF0000) == (addr & 0xFFFF0000))
{
return 0;
}
HMODULE res = (LOADLIB(Real_LoadLibraryExW)) (
lpwLibFileName,
hFile,
dwFlags);
return res;
}
BOOL ProcessAttach()
{
DetourFunctionWithTrampoline((PBYTE)Real_LoadLibraryExW,
(PBYTE)Mine_LoadLibraryExW);
return TRUE;
}
BOOL ProcessDetach()
{
DetourRemove((PBYTE)Real_LoadLibraryExW,
(PBYTE)Mine_LoadLibraryExW);
return TRUE;
}
CAnti_HookApp::CAnti_HookApp() //在使用用户界面服务前调用ProcessAttach
{
user32 = (ULONG)GetModuleHandle("User32.dll");
ProcessAttach();
}
防止全局钩子的侵入
Author: pjf(jfpan20000@sina.com)
Windows消息钩子一般都很熟悉了。它的用处很多,耳熟能详的就有——利用键盘钩子获取目标进程的键盘输入,从而获得各类密码以达到不可告人的目的。朋友想让他的软件不被别人的全局钩子监视,有没有办法实现呢?答案是肯定的,不过缺陷也是有的。
首先简单看看全局钩子如何注入别的进程。
消息钩子是由Win32子系统提供,其核心部分通过NtUserSetWindowsHookEx为用户提供了设置消息钩子的系统服务,用户通过它注册全局钩子。当系统获取某些事件,比如用户按键,键盘driver将扫描码等传入win32k的KeyEvent处理函数,处理函数判断有无相应hook,有则callhook。此时,系统取得Hook对象信息,若目标进程没有装载对应的Dll,则装载之(利用KeUserModeCallback“调用”用户例程,它与Apc调用不同,它是仿制中断返回环境,其调用是“立即”性质的)。
进入用户态的KiUserCallbackDispatcher后,KiUserCallbackDispatcher根据传递的数据获取所需调用的函数、参数等,随后调用。针对上面的例子,为装载hook dll,得到调用的是LoadLibraryExW,随后进入LdrLoadDll,装载完毕后返回,后面的步骤就不叙述了。
从上面的讨论我们可以得出一个最简单的防侵入方案:在加载hook dll之前hook相应api使得加载失败,不过有一个缺陷:系统并不会因为一次的失败而放弃,每次有消息产生欲call hook时系统都会试图在你的进程加载dll,这对于性能有些微影响,不过应该感觉不到。剩下一个问题就是不是所有的LoadLibraryExW都应拦截,这个容易解决,比如判断返回地址。下面给出一个例子片断,可以添加一些判断使得某些允许加载的hook dll被加载。
这里hook api使用了微软的detours库,可自行修改。
以下内容为程序代码:
typedef HMODULE (__stdcall *LOADLIB)(
LPCWSTR lpwLibFileName,
HANDLE hFile,
DWORD dwFlags);
extern "C" {
DETOUR_TRAMPOLINE(HMODULE __stdcall Real_LoadLibraryExW(
LPCWSTR lpwLibFileName,
HANDLE hFile,
DWORD dwFlags),
LoadLibraryExW);
}
ULONG user32 = 0;
HMODULE __stdcall Mine_LoadLibraryExW(
LPCWSTR lpwLibFileName,
HANDLE hFile,
DWORD dwFlags)
{
ULONG addr;
_asm mov eax, [ebp+4]
_asm mov addr, eax
if ((user32 & 0xFFFF0000) == (addr & 0xFFFF0000))
{
return 0;
}
HMODULE res = (LOADLIB(Real_LoadLibraryExW)) (
lpwLibFileName,
hFile,
dwFlags);
return res;
}
BOOL ProcessAttach()
{
DetourFunctionWithTrampoline((PBYTE)Real_LoadLibraryExW,
(PBYTE)Mine_LoadLibraryExW);
return TRUE;
}
BOOL ProcessDetach()
{
DetourRemove((PBYTE)Real_LoadLibraryExW,
(PBYTE)Mine_LoadLibraryExW);
return TRUE;
}
CAnti_HookApp::CAnti_HookApp() //在使用用户界面服务前调用ProcessAttach
{
user32 = (ULONG)GetModuleHandle("User32.dll");
ProcessAttach();
}
#18
to yafizyh(亚斐):
不好意思,我跑题了……
不好意思,我跑题了……
#19
多谢楼主分享
#20
up,mark,concern
#21
WINDOWS核心编程里的用IAT的APIHOOK是不全面的。
::GetProcAddress(::GetModuleHandle("kernel32.dll"), "SetWindowsHookA");
就可以绕过。
APIHOOK最好的方法还是直接修改API入口点的代码。
大家可以参考HXDEF(黑客守卫者)的原代码
::GetProcAddress(::GetModuleHandle("kernel32.dll"), "SetWindowsHookA");
就可以绕过。
APIHOOK最好的方法还是直接修改API入口点的代码。
大家可以参考HXDEF(黑客守卫者)的原代码
#22
mark
#23
up
#24
mark
#25
mark
#26
mark
#27
gz
#28
Very good!
mark
mark
#29
我现在也在用HOOK.
#30
严重收藏................................
#31
mark
#32
=======================
WINDOWS核心编程里的用IAT的APIHOOK是不全面的。
::GetProcAddress(::GetModuleHandle("kernel32.dll"), "SetWindowsHookA");
就可以绕过。
APIHOOK最好的方法还是直接修改API入口点的代码。
大家可以参考HXDEF(黑客守卫者)的原代码
=======================
同时HOOK GetProcAddress 不就行了,但是要是对方使用搜索PE函数导出表的话就没用了
WINDOWS核心编程里的用IAT的APIHOOK是不全面的。
::GetProcAddress(::GetModuleHandle("kernel32.dll"), "SetWindowsHookA");
就可以绕过。
APIHOOK最好的方法还是直接修改API入口点的代码。
大家可以参考HXDEF(黑客守卫者)的原代码
=======================
同时HOOK GetProcAddress 不就行了,但是要是对方使用搜索PE函数导出表的话就没用了
#33
一伙强人在比拼,我MARK一下。慢慢看。
#34
好贴~~~ mark
#35
好贴~~~ mark
#36
好 文章 顶 顶 顶
#37
mark
#38
mark
#39
呵呵,到此一游~签名!
#40
好贴~~~
我喜欢。
我喜欢。
#41
楼主说remote类型的钩子必须放在DLL里面,日志钩子也应属全局钩子吧。它是不需放DLL中的
#42
收藏!
#43
不错
#44
..
#45
MARK
#46
楼主说remote类型的钩子必须放在DLL里面,日志钩子也应属全局钩子吧。它是不需放DLL中的
两个local system-wide hook例外,无关主题
两个local system-wide hook例外,无关主题
#47
mark
#48
mark
#49
NB
#50
mark