//----------------------------------------------------
NTSYSAPI
NTSTATUS
NTAPI ZwQuerySystemInformation(
IN ULONG SystemInformationClass,
IN PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength);
NTSTATUS
NtOpenFile(
OUT PHANDLE FileHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN ULONG ShareAccess,
IN ULONG OpenOptions
);
NTSTATUS
ZwOpenProcess(
OUT PHANDLE ProcessHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN PCLIENT_ID ClientId
);
NTSTATUS
PsLookupProcessByProcessId(
IN HANDLE ProcessId,
OUT PEPROCESS *Process
);
HANDLE
PsGetProcessId(
IN PEPROCESS Process
);
NTSTATUS
RtlFormatCurrentUserKeyPath(
OUT PUNICODE_STRING CurrentUserKeyPath
);
VOID KeAttachProcess( PEPROCESS proc );
VOID KeDetachProcess();
NTSTATUS
ObReferenceObjectByName(
IN PUNICODE_STRING ObjectName,
IN ULONG Attributes,
IN PACCESS_STATE PassedAccessState OPTIONAL,
IN ACCESS_MASK DesiredAccess OPTIONAL,
IN POBJECT_TYPE ObjectType,
IN KPROCESSOR_MODE AccessMode,
IN OUT PVOID ParseContext OPTIONAL,
OUT PVOID *Object
);
//
// 写保护的开&关
void WPOFF();
void WPON();
windows vc 编程---hook[钩子]
fazi 发表于 2005-10-31 9:07:00
什么是“跨进程 API Hook”?
众所周知 Windows 应用程序的各种系统功能是通过调用 API 函数来实现。API Hook 就是给系统的 API
附加上一段小程序,它能监视甚至控制应用程序对 API 函数的调用。所谓跨进程也就是让自己的程序来控
制别人程序的 API 调用了。
API Hook 理论
通 过对 Win32 PE 文件的分析(如果你还不熟悉 PE 文件格式,可以看看 Iczelion 的 PE 教程或者
LUEVELSMEYER 的<>)。 我们知道在 PE 文件中的 IMPORT TABLE 内存储着 API 函数的很多信息。其
中包括 API 的函数名,调用地址等等。而操作系统在执行 PE 文件时会先 将其映射到内存中。在映射的同
时还会把当前版本操作系统中 API 函数的入口地址写入 IMPORT TABLE 中一组与 API 调用相关的结构体
内,用于该应 用程序的 API 调用。 当应用程序调用 API 时,他会在自己内存映像里寻找 API 的入口地址,
然后执行 CALL 指令。如此一来,我们通过修改应用程序内存 映像的 IMPORT TABLE 中 API 函数的入口
地址,就可以达到重定向 API 的目的。将 API 地址改为我们自己函数的地址,这样我们的函数就可以完成
对 API 的监视和控制了。
// 本 文 转 自 C++Bui l der 研究 - ht t p: / / www. ccrun. com/ ar t i cl e. asp?i =1036&d=cf6de2
始 化 的 ,“ 两 个 结 构 都 指 向 同 一 个 I MAGE _ I MP ORT_ B Y_ NAME ” ,此 时 还 没 有 api 函 数 地 址
作者:佚名 来源:不详 点击:131 更新:2006-12-19 7:01:28 编辑: 画王 w 字体:小 大
都是很成熟的东西了,这几天看了看,总结一下而已。
讨论了 Windows 下 hook 函数的几种方法。提供了一个 hook TextOutA 的完整例子。通过 CreateRemoteThread 的方法把 hook dll 注入到一个普
通的应用程序中。Hooking Imported Functions by name 调用 imported functions'时的步骤/实现在程序中调用从其它模块引入的函数的方法和普
通的函数调用有所不同。对于普通的函数调用,直接使用 call address 来调用即可,但是对于 imported functions ,在编译的时候 compiler/link
并不知道实际的函数实现会被加载到那个地址,函数实现在那个地址在运行的时候才会确定。对于 imported functions ,首先是 call 引入表中的
一个函数,在运行时再初始化引入表,使用 jmp 跳转到真实的函数实现。
引入表:
The PE file IMAGE_IMPORT_DESCRIPTOR structure, which holds all the information about functions imported from a specifi
c DLL, has pointers to two arrays in the executable. These arrays are called import address tables (IATs), or sometimes thunk
data arrays. The first pointer references the real IAT, which the program loader fixes up when the executable is loaded. The
second pointer references the original IAT, which is untouched by the loader and lists the imported functions.
实现原理
找到 PE 文件的 Image_Import_Descriptor 结构
找到 Original LAT 和 Real LAT.
通过要 hook 的函数的名字在 Original LAT 找到要 hook 的 imported function 在数组中的 index.
保存并修改 Real LAT 在相应 index 的 function address
(refer to John Robbins, BugsLayerUtil.dll)
Hooking Imported Functions by ordinal
原理和 Hook Imported functions by name 一样,只是是通过要 hook 的函数的 ordinal 在 original LAT 中找到 index.
Hooking a function in this dll
当一个 DLL 是通过 LoadLibrary 载入的时候,我们无法通过 hook imported function 的方法的 hook 它中的 function
。有两种可能的办法处理这种情况:
第一种方法,遍历进程空间,发现 call 指定函数的地方替换为 call hookFunction. 太麻烦,而且不安全。
第二种方法,改写要 hook 的函数 FuncA
。比较好的方法
1. 实现 HookFuncA ,最后的实现垫入 n 个 nop.
2. 找到要 hook 的函数 FuncA 的绝对地址,改写前 5 个字节为 jmp hookFuncA( 假定前 5 个字节为 n 个完整的指令)
3. 把 FuncA 的前 5 个字节拷贝到 hookFuncA 的后面,在加上一条指令 jmp funcA+5.
----Code of HookDLL.dll, 可以通过 CreateRemoteThread 的方法把 hook dll 注入到一个普通的应用程序中。
// HookDLL.cpp : Defines the entry point for the DLL application.
//
#include "stdafx.h"
#include "HookDLL.h"
#include "Log.h"
//forward declare.
LRESULT WINAPI InstallTextoutHook();
LRESULT WINAPI UninstallTextoutHook();
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
if (InstallTextoutHook())
{
WriteLog("Install hook success.\n");
}else
{
WriteLog("Intall hook failed.\n");
}
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
if (UninstallTextoutHook())
{
WriteLog("Uninstall hook success.\n");
}else
{
WriteLog("Unintall hook failed.\n");
}
break;
}
return TRUE;
}
#define DWORD_PTR DWORD*
#define __LOCAL_SIZE 40h
#define NAKED_PROLOG() \
DWORD_PTR dwRet ; \
DWORD_PTR dwESI ; \
{ \
__asm PUSH EBP /* Set up the standard frame.*/\
__asm MOV EBP , ESP \
__asm SUB ESP , __LOCAL_SIZE /* Save room for the local */\
/* variables. */\
__asm MOV EAX , EBP /* EBP has the stack coming */\
/* into the fn. in it. */\
__asm ADD EAX , 4 /* Account for PUSH EBP */\
__asm MOV EAX , [EAX] /* Get return address. */\
__asm MOV [dwRet] , EAX /* Save return address. */\
__asm MOV [dwESI] , ESI /* Save ESI so chkesp in dbg */\
/* builds works. */\
}// The common epilog part that can be shared between the stdcall and
// cdecl hook functions.
#define EPILOG_COMMON() \
{ \
__asm MOV ESI , [dwESI] /* Restore ESI. */\
__asm ADD ESP , __LOCAL_SIZE /* Take away local var space */\
__asm MOV ESP, EBP /* Restore standard frame. */\
__asm POP EBP \
}
#define COPY_CODE_LENGTH 5
BYTE g_abOriCode[COPY_CODE_LENGTH];
BYTE g_abJmpCode[COPY_CODE_LENGTH];
PROC g_oriTextout;
BOOL g_blHooked = FALSE;
LRESULT WINAPI InstallTextoutHook()
{
if (g_blHooked)
return TRUE;
//Get TextOutA's address.
HMODULE hGdi32 = ::LoadLibrary(_T("Gdi32.dll"));
g_oriTextout = GetProcAddress(hGdi32, _T("TextOutA"));
if (NULL == g_oriTextout)
return FALSE;
//Get the hook'a address.
HMODULE hModule = GetModuleHandle(_T("HookDLL.dll"));
if (NULL == hModule)
return FALSE;
DWORD dwHookAddr = NULL;
__asm
{
mov esi, offset HookLabel;
mov edi, 0x10000000;//0x10000000 is the dll's base address.
sub esi, edi;
add esi, hModule;
mov [dwHookAddr], esi;
}
//Get the NOP's address.
DWORD dwNOPAddr = NULL;
__asm
{
mov esi, offset NOPLabel;
mov edi, 0x10000000;//0x10000000 is the dll's base address.
sub esi, edi;
add esi, hModule;
mov [dwNOPAddr], esi;
}
//Save the first 5 byte of TextOutA to g_abOriCode
__asm
{
mov esi, g_oriTextout;
lea edi, g_abOriCode;
cld;
movsd;
movsb;
}
//Generate the jmp Hook function.
g_abJmpCode[0] = 0xe9;
__asm
{
mov eax, dwHookAddr;
mov ebx, g_oriTextout;
add ebx, 5;
sub eax, ebx;
mov dword ptr[g_abJmpCode+1], eax;
}
//Write the jump instruction to the textoutA.
DWORD dwProcessId = GetCurrentProcessId();
HANDLE hProcess = OpenProcess (PROCESS_ALL_ACCESS,
FALSE, dwProcessId);
if (NULL == hProcess)
return FALSE;
DWORD dwOldFlag;
VirtualProtectEx(hProcess, g_oriTextout, 5, PAGE_READWRITE, &dwOldFlag);
WriteProcessMemory(hProcess, g_oriTextout, g_abJmpCode, sizeof(g_abJmpCode), NULL);
VirtualProtectEx(hProcess, g_oriTextout, 5, dwOldFlag, NULL);
//Write g_abOriTextout to the end of Hook function(NOP addr), then write the jmp instruction.
VirtualProtectEx(hProcess, (LPVOID)dwNOPAddr, 10, PAGE_READWRITE, &dwOldFlag);
WriteProcessMemory(hProcess, (LPVOID)dwNOPAddr, g_abOriCode, sizeof(g_abOriCode), NULL);
//Generate the jmp TextoutA + 5
__asm
{
mov eax, g_oriTextout;
mov ebx, dwNOPAddr;
add ebx, 5;
sub eax, ebx;
mov dword ptr[g_abJmpCode+1], eax;
}
WriteProcessMemory(hProcess, (LPVOID)(dwNOPAddr+5), g_abJmpCode, sizeof(g_abJmpCode), NULL);
VirtualProtectEx(hProcess, (LPVOID)dwNOPAddr, 10, dwOldFlag, NULL);
g_blHooked = TRUE;
if(TRUE)
return TRUE;
HookLabel:
NAKED_PROLOG ( ) ;
int nx, ny;
LPCSTR lp;
lp = NULL;
_asm
{
mov esi, ebp;
add esi, 0Ch;
lea edi, nx;
movsd;
lea edi, ny;
movsd;
lea edi, lp;
movsd;
}
WriteLog_F("Try to ouput \"%s\" at (%d,%d)\n", lp, nx, ny);
// Do the common epilog.
EPILOG_COMMON ( ) ;
NOPLabel:
_asm NOP
_asm NOP
_asm NOP
_asm NOP
_asm NOP
_asm NOP
_asm NOP
_asm NOP
_asm NOP
_asm NOP
_asm NOP
}
LRESULT WINAPI UninstallTextoutHook()
{
if (!g_blHooked)
return FALSE;
//Restore the first 5 bytes code of TextOutA
DWORD dwProcessId = GetCurrentProcessId();
HANDLE hProcess = OpenProcess (PROCESS_ALL_ACCESS,
FALSE, dwProcessId);
if (NULL == hProcess)
return FALSE;
DWORD dwOldFlag;
VirtualProtectEx(hProcess, g_oriTextout, 5, PAGE_READWRITE, &dwOldFlag);
WriteProcessMemory(hProcess, g_oriTextout, g_abOriCode, sizeof(g_abOriCode), NULL);
VirtualProtectEx(hProcess, g_oriTextout, 5, dwOldFlag, NULL);
g_blHooked = FALSE;
return TRUE;
}
VC 实现的 MSN Messager 钩子程序
2005-11-02 15:38 来源:CSDN RSS 复制链接打印
核心提示:
最近研究怎么样使用 HOOK 拦截其他应用程序的消息,于是就动手写了一个钩子程序来挂到最常
用的通讯及时通讯工具 MSN,虽然没有什么实际意义,但作为学习研究却能够帮助我们理解利用 HOOK 是怎
么样将自己编写的 DLL 注入已经存在的程序空间中的。
我们需要做的是通过我们自己编写的应用程序去拦截别人写好的应用程序消息,实际上这是在
两个进程之间进行的,难度就在这里,如果是同一个进程什么都好办,只要将系统响应 WINDOWS 消息的处
理函数修改为我们自己编写的函数就可以,但现在不能这么做,因为两个进程有各自的进程地址空间,理
论上你没有办法直接去访问别的进程的地址空间,那么怎么办来?办法还是很多的,这里仅仅介绍通过 HO
OK 来达到目的。
'当 vc dll 用 Unicode 时:
'Private Declare Sub sethook_kb Lib "hook" (ByVal strlen As Integer, ByVal astr As Long)
'调用部分变为 sethook_kb Len(str), StrPtr(str) 只有这样才不会出乱码
Private Declare Sub sethook Lib "hook" (ByVal astr As String)
Private Declare Sub unhook Lib "hook" ()
Private Declare Sub hookdlltest Lib "hook" ()
Private a As String
Private Sub Command1_Click()
Dim str As String
str = "我们的故事 99999999999999999"
sethook str
'sethook_kb Len(str), str
End Sub
Private Sub Command2_Click()
' MsgBox CStr(Len("我们"))
unhook
End Sub
Private Sub Form_Load()
hd
End Sub
Private Sub hd()
End Sub
(1)用 MFC 的 AppWizard(EXE)创建项目 Mouse;
(2)选择“基于对话应用”并按下“完成”键;
(3)编辑对话框,删除其中原有的两个按钮,加入静态文本框和编辑框,用鼠标右键点击静态文本框,
在弹出的菜单中选择“属性”,设置其标题为“鼠标所在的窗口标题”;
(4)在 Mouse.h 中加入对 Mousehook.h 的包含语句#Include"..\Mousehook\Mousehook.h";
(5)在 CMouseDlg.h 的 CMouseDlg 类定义中添加私有数据成员:
CMouseHook m_hook;//加入钩子类作为数据成员
(6)修改 CmouseDlg::OnInitDialog()函数:
BOOL CMouseDlg::OnInitDialog()
{
CDialog::OnInitDialog();
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
SetIcon(m_hIcon, TRUE);//Set big icon
SetIcon(m_hIcon, FALSE);//Set small icon
//TODO: Add extra initialization here
CWnd * pwnd=GetDlgItem(IDC_EDIT1);
//取得编辑框的类指针
m_hook.starthook(pwnd->GetSafeHwnd());
//取得编辑框的窗口句柄并安装钩子
return TRUE;
//return TRUE unless you set the focus to a control
}
(7)链接 DLL 库,即把..\Mousehook\debug\Mousehook.lib 加入到项目设置链接标签中;
(8)编译项目生成可执行文件;
(9)把 Mousehook.DLL 拷贝到..\mouse\debug 目录中;
(10)先运行几个可执行程序,然后运行 Mouse.exe 程序,把鼠标在不同窗口中移动,在 Mouse.exe 程序
窗口中的编辑框内将显示出鼠标所在的应用程序主窗口的标题。
钩子概述 MSDN <英>
A hook is a mechanism by which an application can intercept events, such as messages, mouse
actions, and keystrokes. A function that intercepts a particular type of event is known as a hook
procedure. A hook procedure can act on each event it receives, and then modify or discard the
event.
The following some example uses for hooks:
Monitor messages for debugging purposes
Provide support for recording and playback of macros
Provide support for a help key (F1)
Simulate mouse and keyboard input
Implement a computer-based training (CBT) application
Note Hooks tend to slow down the system because they increase the amount of processing the system must
perform for each message. You should install a hook only when necessary, and remove it as soon as possible.
This section discusses the following:
Hook Chains
Hook Procedures
Hook Types
Hook Chains
o WH_CALLWNDPROC and WH_CALLWNDPROCRET
o WH_CBT
o WH_DEBUG
o WH_FOREGROUNDIDLE
o WH_GETMESSAGE
o WH_JOURNALPLAYBACK
o WH_JOURNALRECORD
o WH_KEYBOARD_LL
o WH_KEYBOARD
o WH_MOUSE_LL
o WH_MOUSE
o WH_MSGFILTER and WH_SYSMSGFILTER
o WH_SHELL
The system supports many different types of hooks; each type provides access to a different aspect of its
message-handling mechanism. For example, an application can use the WH_MOUSE hook to monitor the message
traffic for mouse messages.
The system maintains a separate hook chain for each type of hook. A hook chain is a list of pointers to special,
application-defined callback functions called hook procedures. When a message occurs that is associated with a
particular type of hook, the system passes the message to each hook procedure referenced in the hook chain, one
after the other. The action a hook procedure can take depends on the type of hook involved. The hook procedures
for some types of hooks can only monitor messages; others can modify messages or stop their progress through the
chain, preventing them from reaching the next hook procedure or the destination window.
Hook Procedures
To take advantage of a particular type of hook, the developer provides a hook procedure and uses
the SetWindowsHookEx function to install it into the chain associated with the hook. A hook procedure must
have the following syntax:
Copy
LRESULT CALLBACK HookProc(
int nCode,
WPARAM wParam,
LPARAM lParam
)
{
// process event
...
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
HookProc is a placeholder for an application-defined name.
The nCode parameter is a hook code that the hook procedure uses to determine the action to perform. The value of
the hook code depends on the type of the hook; each type has its own characteristic set of hook codes. The values
of the wParam and lParam parameters depend on the hook code, but they typically contain information about a
message that was sent or posted.
The SetWindowsHookEx function always installs a hook procedure at the beginning of a hook chain. When an
event occurs that is monitored by a particular type of hook, the system calls the procedure at the beginning of the
hook chain associated with the hook. Each hook procedure in the chain determines whether to pass the event to the
next procedure. A hook procedure passes an event to the next procedure by calling the CallNextHookEx function.
Note that the hook procedures for some types of hooks can only monitor messages. the system passes messages to
each hook procedure, regardless of whether a particular procedure calls CallNextHookEx.
A global hook monitors messages for all threads in the same desktop as the calling thread. A thread-specific
hook monitors messages for only an individual thread. A global hook procedure can be called in the context of any
application in the same desktop as the calling thread, so the procedure must be in a separate DLL module. A
thread-specific hook procedure is called only in the context of the associated thread. If an application installs a
hook procedure for one of its own threads, the hook procedure can be in either the same module as the rest of the
application's code or in a DLL. If the application installs a hook procedure for a thread of a different application,
the procedure must be in a DLL. For information, see Dynamic-Link Libraries.
Note You should use global hooks only for debugging purposes; otherwise, you should avoid them. Global
hooks hurt system performance and cause conflicts with other applications that implement the same type of global
hook.
Hook Types
Each type of hook enables an application to monitor a different aspect of the system's message-handling
mechanism. The following sections describe the available hooks.
WH_CALLWNDPROC and WH_CALLWNDPROCRET
WH_CBT
WH_DEBUG
WH_FOREGROUNDIDLE
WH_GETMESSAGE
WH_JOURNALPLAYBACK
WH_JOURNALRECORD
WH_KEYBOARD_LL
WH_KEYBOARD
WH_MOUSE_LL
WH_MOUSE
WH_MSGFILTER and WH_SYSMSGFILTER
WH_SHELL
WH_CALLWNDPROC and WH_CALLWNDPROCRET
The WH_CALLWNDPROC and WH_CALLWNDPROCRET hooks enable you to monitor messages sent to
window procedures. The system calls a WH_CALLWNDPROC hook procedure before passing the message to
the receiving window procedure, and calls the WH_CALLWNDPROCRET hook procedure after the window
procedure has processed the message.
The WH_CALLWNDPROCRET hook passes a pointer to a CWPRETSTRUCT structure to the hook
procedure. The structure contains the return value from the window procedure that processed the message, as well
as the message parameters associated with the message. Subclassing the window does not work for messages set
between processes.
For more information, see the CallWndProc and CallWndRetProc callback functions.
WH_CBT
The system calls a WH_CBT hook procedure before activating, creating, destroying, minimizing, maximizing,
moving, or sizing a window; before completing a system command; before removing a mouse or keyboard event
from the system message queue; before setting the input focus; or before synchronizing with the system message
queue. The value the hook procedure returns determines whether the system allows or prevents one of these
operations. The WH_CBT hook is intended primarily for computer-based training (CBT) applications.
For more information, see the CBTProc callback function.
For information, see WinEvents.
WH_DEBUG
The system calls a WH_DEBUG hook procedure before calling hook procedures associated with any other hook
in the system. You can use this hook to determine whether to allow the system to call hook procedures associated
with other types of hooks.
For more information, see the DebugProc callback function.
WH_FOREGROUNDIDLE
The WH_FOREGROUNDIDLE hook enables you to perform low priority tasks during times when its
foreground thread is idle. The system calls a WH_FOREGROUNDIDLE hook procedure when the application's
foreground thread is about to become idle.
For more information, see the ForegroundIdleProc callback function.
WH_GETMESSAGE
The WH_GETMESSAGE hook enables an application to monitor messages about to be returned by
the GetMessage or PeekMessage function. You can use the WH_GETMESSAGEhook to monitor mouse and
keyboard input and other messages posted to the message queue.
For more information, see the GetMsgProc callback function.
WH_JOURNALPLAYBACK
The WH_JOURNALPLAYBACK hook enables an application to insert messages into the system message queue.
You can use this hook to play back a series of mouse and keyboard events recorded earlier by
using WH_JOURNALRECORD. Regular mouse and keyboard input is disabled as long as
a WH_JOURNALPLAYBACK hook is installed. AWH_JOURNALPLAYBACK hook is a global hook—it
cannot be used as a thread-specific hook.
The WH_JOURNALPLAYBACK hook returns a time-out value. This value tells the system how many
milliseconds to wait before processing the current message from the playback hook. This enables the hook to
control the timing of the events it plays back.
For more information, see the JournalPlaybackProc callback function.
WH_JOURNALRECORD
The WH_JOURNALRECORD hook enables you to monitor and record input events. Typically, you use this
hook to record a sequence of mouse and keyboard events to play back later by using WH_JOURNALPLAYBACK.
The WH_JOURNALRECORD hook is a global hook—it cannot be used as a thread-specific hook.
For more information, see the JournalRecordProc callback function.
WH_KEYBOARD_LL
The WH_KEYBOARD_LL hook enables you to monitor keyboard input events about to be posted in a thread
input queue.
For more information, see the LowLevelKeyboardProc callback function.
WH_KEYBOARD
The WH_KEYBOARD hook enables an application to monitor message traffic
for WM_KEYDOWN and WM_KEYUP messages about to be returned by
the GetMessage orPeekMessage function. You can use the WH_KEYBOARD hook to monitor keyboard input
posted to a message queue.
For more information, see the KeyboardProc callback function.
WH_MOUSE_LL
The WH_MOUSE_LL hook enables you to monitor mouse input events about to be posted in a thread input
queue.
For more information, see the LowLevelMouseProc callback function.
WH_MOUSE
The WH_MOUSE hook enables you to monitor mouse messages about to be returned by
the GetMessage or PeekMessage function. You can use the WH_MOUSE hook to monitor mouse input posted to
a message queue.
For more information, see the MouseProc callback function.
WH_MSGFILTER and WH_SYSMSGFILTER
The WH_MSGFILTER and WH_SYSMSGFILTER hooks enable you to monitor messages about to be
processed by a menu, scroll bar, message box, or dialog box, and to detect when a different window is about to be
activated as a result of the user's pressing the ALT+TAB or ALT+ESC key combination.
The WH_MSGFILTER hook can only monitor messages passed to a menu, scroll bar, message box, or dialog
box created by the application that installed the hook procedure. The WH_SYSMSGFILTER hook monitors such
messages for all applications.
The WH_MSGFILTER and WH_SYSMSGFILTER hooks enable you to perform message filtering during
modal loops that is equivalent to the filtering done in the main message loop. For example, an application often
examines a new message in the main loop between the time it retrieves the message from the queue and the time it
dispatches the message, performing special processing as appropriate. However, during a modal loop, the system
retrieves and dispatches messages without allowing an application the chance to filter the messages in its main
message loop. If an application installs a WH_MSGFILTER or WH_SYSMSGFILTER hook procedure, the
system calls the procedure during the modal loop.
An application can call the WH_MSGFILTER hook directly by calling the CallMsgFilter function. By using this
function, the application can use the same code to filter messages during modal loops as it uses in the main
message loop. To do so, encapsulate the filtering operations in a WH_MSGFILTER hook procedure and
callCallMsgFilter between the calls to the GetMessage and DispatchMessage functions.
Copy
while (GetMessage(&msg, (HWND) NULL, 0, 0))
{
if (!CallMsgFilter(&qmsg, 0))
DispatchMessage(&qmsg);
}
The last argument of CallMsgFilter is simply passed to the hook procedure; you can enter any value. The hook
procedure, by defining a constant such asMSGF_MAINLOOP, can use this value to determine where the
procedure was called from.
For more information, see the MessageProc and SysMsgProc callback functions.
WH_SHELL
A shell application can use the WH_SHELL hook to receive important notifications. The system calls
a WH_SHELL hook procedure when the shell application is about to be activated and when a top-level window is
created or destroyed.
Note that custom shell applications do not receive WH_SHELL messages. Therefore, any application that
registers itself as the default shell must call theSystemParametersInfo function before it (or any other application)
can receive WH_SHELL messages. This function must be called with SPI_SETMINIMIZEDMETRICS and
a MINIMIZEDMETRICS structure. Set the iArrange member of this structure to ARW_HIDE.
For more information, see the ShellProc callback function.
钩子概述 MSDN <中>
一个钩是一种机制,使应用程序可以拦截事件,如邮件,鼠标操作和键盘敲击。一个功能,它可以拦截特
定类型的事件被称为一个钩子程序。钩子程序可以作用于它接收到的每个事件,然后修改或放弃的事件。
下面的一些例子使用钩子:
调试的目的监视消息
提供支持宏的录制和播放
提供支持,帮助键(F1)
模拟鼠标和键盘输入。
实现基于计算机的培训(CBT)的应用
注 挂钩往往会拖慢系统,因为它们增加了系统处理量必须执行的每个消息。你应该安装一个挂钩,只在
必要时,并尽快将其删除。
本节将讨论以下内容:
钩链
钩链
钩子程序
钩子类型
o WH_CALLWNDPROC 和 WH_CALLWNDPROCRET
o WH_CBT
o WH_DEBUG
o WH_FOREGROUNDIDLE
o WH_GETMESSAGE
o WH_JOURNALPLAYBACK
o WH_JOURNALRECORD
o WH_KEYBOARD_LL
o WH_KEYBOARD
o WH_MOUSE_LL
o WH_MOUSE
o WH_MSGFILTER 和 WH_SYSMSGFILTER
o WH_SHELL
该系统支持多种不同类型的钩子;每个类型提供访问其消息处理机制的一个不同方面。例如,一个应用程序
可以使用 WH_MOUSE 钩子来监视鼠标消息的消息流量。
该系统保持一个单独的钩链,为每种类型的钩子。一个 钩子链是一个特殊的,应用程序定义的回调函数称
为钩子程序的指针列表 。当一个消息发生,是与特定类型的钩子,该系统将消息传递到每个钩子程序中引
用的钩链,一前一后。一个钩子程序可以采取的行动取决于所涉及的类型的钩子。对于某些类型的钩子只
能监视钩子程序的消息,其他人可以修改消息或停止其进展情况,通过连锁经营,防止他们到达下一个钩
子程序或目标窗口。
钩子程序
若要利用一种特定类型的钩,显影剂提供了一个钩子程序,并使用调用 SetWindowsHookEx 函数,把它安
装到钩与链。一个钩子过程必须有下面的语法:
复制
LRESULT CALLBACK HOOKPROC(
诠释 nCode,
WPARAM wParam 参数,
LPARAM lParam 的
)
{
/ /处理事件
...
// Initialize structures with hook data. The menu-item
// identifiers are defined as 0 through 6 in the
// header file. They can be used to identify array
// elements both here and during the WM_COMMAND
// message.
关于 SetWindowsHookEx 情况 MSDN,我这里引入了一个论坛上的内容,请耐心阅读
********************************************************************************
This article was contributed by Robert Wiejak.
Environment: MFC, Windows 95, 98, Me, NT 3.51, 4.0, 5.0
If you spend time investigating what happens when you click and release the left
button over the title bar, you will find out that instead of getting "non-client
left button up " message, you just get "left button up
". One could actually work with it, if the message found it
's way into the application. It does not.
I was in a middle of writing an application when I discovered this. I looked all
over the internet for articles regarding WM_NCLBUTTONUP problem, but the only
thing I could find were questions about the problem. After some more investigating
I have come up with a patch that could be adopted by each application requ
iring such notification.
The patch consists of installing a "windows hook
" that will intercept all mouse messages for this application before they enter int
o the message pump. To do that you need to call SetWindowsHookEx(...) function,
soon after the main window is created. Here is the call:
hMHook = SetWindowsHookEx(
// hook type:
WH_MOUSE,
// hook procedure:
(HOOKPROC) MouseHookProc,
// handle to application instance:
AfxGetInstanceHandle(),
// thread identifier:
AfxGetThread()-> m_nThreadID
);
It is very important that you supply handle to application instance and thread ide
ntifier, otherwise every application running on your computer will attempt to hook i
t
's mouse messages through your program and it could be disastrous. By supplying
these two parameters you will insure that only messages from your application will
end up in your callback function.
Equally important is a call to remove the hook before your application terminates.
The UnhookWindowsHookEx(...) function removes a hook procedure installed in a hook
chain. Most likely you will call it somewhere in OnDestroy(), like this:
if(hMHook != NULL)
UnhookWindowsHookEx(hMHook);
The callback function is where you will receive WM_NCLBUTTONDOWN message and
the next time you receive WM_LBUTTONUP message you will post WM_NCLBUTTONUP
directly into the application message pump. Therefore, no special handling will be
required to service these messages. You will simply write your code inside of O
nNcLButtonUp(...), just like you would for any other message.
Here is the callback code:
//
// handle to the mouse hook
HHOOK hMHook = NULL;
// status of non-client left button down
BOOL bNcLButtonDown = FALSE;
// /
// Mouse hook process
LRESULT CALLBACK MouseHookProc( int nCode,
WPARAM wParam,
LPARAM lParam)
{
if(nCode == HC_ACTION)
{
// get a pointer to the mouse hook struct.
PMOUSEHOOKSTRUCT mhs = (PMOUSEHOOKSTRUCT) lParam;
// intercept messages for left button down and up
switch(wParam)
{
case WM_NCLBUTTONDOWN:
{
// get the pointer to the main window
CWnd *pWnd = AfxGetMainWnd();
// if the message is from your window and
// the hit test indicates title bar
if((mhs-> hwnd == pWnd-> GetSafeHwnd())
&& (mhs-> wHitTestCode == HTCAPTION))
{
// then indicate non-client left button down
bNcLButtonDown = TRUE;
// there is no problem with this message
// so you don 't have to do anything else
}
}
break;
case WM_NCLBUTTONUP:
// you will get this message if you double-click
// on the title bar
// reset the status
bNcLButtonDown = FALSE;
break;
case WM_LBUTTONUP:
{
// get the pointer to the main window
CWnd *pWnd = AfxGetMainWnd();
// if the message is from your window and
// non-client left button is down
if((mhs-> hwnd == pWnd-> GetSafeHwnd())
&& (bNcLButtonDown == TRUE))
{
// then post WM_NCLBUTTONUP message directly
// into your window message pump
// Note: I 'm hardcoding HTCAPTION because the
// left button was down, and while it is down,
// the mouse does not move in respect to the
// window, but it does in respect to the screen,
// so the mouse should still be over the caption
// bar of your window when you release the button.
pWnd-> PostMessage(WM_NCLBUTTONUP, HTCAPTION,
MAKELONG(mhs-> pt.x,mhs-> pt.y));
// reset non-client left button down
bNcLButtonDown = FALSE;
}
}
break;
default:
break;
}
}
// let the messages through to the next hook
return CallNextHookEx(hMHook, nCode, wParam, lParam);
}
I am including two sample projects. The "nclbxExample
" is technical, and the "AlphaDialogExample " is more practical. The "nclbxExample
" is better documented so you can see how and were I have implemented the
code.
NOTE: If you are going to use mousepatch.cpp the way I
'm using it, DO NOT add it to your project.
DWORD __stdcall Hook_NtResumeThread(
HANDLE ThreadHandle,
PULONG PreviousSuspendCount OPTIONAL)
{
/*int OldNtResumeThread=0x11223344;//原 NtQueryDirectoryFile 函数
int EventHandle=0x11002200;
int my_GetCurrentProcessId=0x00224466;
int my_SetEnent=0x22447688;
int my_WaitForSingleObject=0x22556577;
int my_NtQueryInformationThread=0x99884756;*/
//int FarRead=0x00220044;
int OldNtResumeThread;//原 NtQueryDirectoryFile 函数
int EventHandle;
int my_GetCurrentProcessId;
int my_SetEnent;
int my_WaitForSingleObject;
int my_NtQueryInformationThread;
int my_ResetEvent;
__asm
{
mov OldNtResumeThread,00112244h
mov EventHandle,00225588h
mov my_GetCurrentProcessId,22447799h
mov my_SetEnent,55662244h
mov my_WaitForSingleObject,55889966h
mov my_NtQueryInformationThread,77554411h
mov my_ResetEvent,55661188h
pushad
}
__asm call GetAddr;
int FarRead;
__asm mov FarRead,22550011h;
DWORD myAddr;
__asm
{
jmp start
GetAddr:
pop eax
mov myAddr,eax
push eax
ret
start:
}
DWORD myStatus;//存储返回变量
BYTE SystemInfo[60];
int infoaddr=(DWORD)&SystemInfo;
int CurrentProcess;