⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lion-tutorial24.htm

📁 内有一些代码
💻 HTM
📖 第 1 页 / 共 3 页
字号:
<html>

<head>
<link rel="stylesheet" href="../../asm.css">

<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>Iczelion's win32 asm tutorial</title>
</head>

<body bgcolor="#FFFFFF" background="../../images/back01.jpg">
<p align="center">Tutorial 24: Windows Hooks</p>
<hr size="1">
We will learn about Windows hooks in this tutorial. Windows hooks are very powerful. 
With them, you can poke inside other processes and sometimes alter their behaviors. 
<br>
Download the example <a href="files/tut24.zip">here</a>. 
<h3> Theory:</h3>
Windows hooks can be considered one of the most powerful features of Windows. 
With them, you can trap events that will occur, either in your own process or 
in other processes. By "hooking", you tell Windows about a function, filter function 
also called hook procedure, that will be called everytime an event you're interested 
in occurs. There are two types of them: local and remote hooks. 
<ul>
  <li> Local hooks trap events that will occur in your own process.</li>
  <li> Remote hooks trap events that will occur in other process(es). There are 
    two types of remote hooks</li>
  <ul>
    <li> thread-specific&nbsp; traps events that will occur in a specific thread 
      in other process. In short, you want to observe events in a specific thread 
      in a specific process.</li>
    <li> system-wide&nbsp; traps all events destined for all threads in all processes 
      in the system.</li>
  </ul>
</ul>
When you install hooks, remember that they affect system performance. System-wide 
hooks are the most notorious. Since ALL related events will be routed through 
your filter function, your system may slow down noticeably. So if you use a system-wide 
hook, you should use it judiciously and unhook it as soon as you don't need it. 
Also, you have a higher chance of crashing the other processes since you can meddle 
with other processes and if something is wrong in your filter function, it can 
pull the other processes down to oblivion with it. Remember: Power comes with 
responsibility. <br>
You have to understand how a hook works before you can use it efficiently. When 
you create a hook, Windows creates a data structure in memory, containing information 
about the hook, and adds it to a linked list of existing hooks. New hook is added 
in front of old hooks. When an event occurs, if you install a local hook, the 
filter function in your process is called so it's rather straightforward. But 
if it's a remote hook, the system must inject the code for the hook procedure 
into the address space(s) of the other process(es). And the system can do that 
only if the function resides in a DLL. Thus , if you want to use a remote hook, 
your hook procedure must reside in a DLL. There is two exceptions to this rule: 
journal record and journal playback hooks. The hook procedures for those two hooks 
must reside in the thread that installs the hooks. The reason why it must be so 
is that: both hooks deal with the low-level interception of hardware input events. 
The input events must be recorded/playbacked in the order they appeared. If the 
code of those two hooks is in a DLL, the input events may scatter among several 
threads and it is impossible to know the order of them. So the solution: the hook 
procedure of those two hooks must be in a single thread only i.e. the thread that 
installs the hooks. <br>
There are 14 types of hooks: 
<ul>
  <li> <b>WH_CALLWNDPROC</b>&nbsp; called when SendMessage is called</li>
  <li> <b>WH_CALLWNDPROCRET</b>&nbsp; called when SendMessage returns</li>
  <li> <b>WH_GETMESSAGE</b>&nbsp;&nbsp; called when GetMessage or PeekMessage 
    is called</li>
  <li> <b>WH_KEYBOARD</b>&nbsp; called when GetMessage or PeekMessage retrieves 
    WM_KEYUP or WM_KEYDOWN from the message queue</li>
  <li> <b>WH_MOUSE</b>&nbsp; called when GetMessage or PeekMessage retrieves a 
    mouse message from the message queue</li>
  <li> <b>WH_HARDWARE</b> called when GetMessage or PeekMessage retrieves some 
    hardware message that is not related to keyboard or mouse.</li>
  <li> <b>WH_MSGFILTER&nbsp;</b> called when a dialog box, menu or scrollbar is 
    about to process a message. This hook is local. It's specifically for those 
    objects which have their own internal message loops.</li>
  <li> <b>WH_SYSMSGFILTER</b>&nbsp; same as WH_MSGFILTER but system-wide</li>
  <li> <b>WH_JOURNALRECORD</b>&nbsp; called when Windows retrieves message from 
    the hardware input queue</li>
  <li> <b>WH_JOURNALPLAYBACK</b>&nbsp; called when an event is requested from 
    the system's hardware input queue.</li>
  <li> <b>WH_SHELL</b>&nbsp; called when something interesting about the shell 
    occurs such as when the task bar needs to redraw its button.</li>
  <li> <b>WH_CBT</b>&nbsp; used specifically for computer-based training (CBT).</li>
  <li> <b>WH_FOREGROUNDIDLE</b> used internally by Windows. Little use for general 
    applications</li>
  <li> <b>WH_DEBUG</b>&nbsp; used to debug the hooking procedure</li>
</ul>
Now that we know some theory, we can move on to how to install/uninstall the hooks. 
<br>
To install a hook, you call SetWindowsHookEx which has the following syntax: 
<blockquote><b>SetWindowsHookEx proto HookType:DWORD, pHookProc:DWORD, hInstance:DWORD, 
  ThreadID:DWORD</b> 
  <ul>
    <li> HookType is one of the values listed above, e.g., <b>WH_MOUSE</b>, <b>WH_KEYBOARD</b></li>
    <li> pHookProc is the address of the hook procedure that will be called to 
      process the messages for the specified hook. If the hook is a remote one, 
      it must reside in a DLL. If not, it must be in your process.</li>
    <li> hInstance is the instance handle of the DLL in which the hook procedure 
      resides. If the hook is a local one, this value must be NULL</li>
    <li> ThreadID&nbsp; is the ID of the thread you want to install the hook to 
      spy on. This parameter is the one that determines whether a hook is local 
      or remote. If this parameter is NULL, Windows will interpret the hook as 
      a system-wide remote hook that affects all threads in the system. If you 
      specify the thread ID of a thread in your own process, this hook is a local 
      one. If you specify the thread ID from other process, the hook is a thread-specific 
      remote one. There are two exceptions to this rule: <b>WH_JOURNALRECORD</b> 
      and <b>WH_JOURNALPLAYBACK</b> are always local system-wide hooks that are 
      not required to be in a DLL. And <b>WH_SYSMSGFILTER</b> is always a system-wide 
      remote hook. Actually it is identical to <b>WH_MSGFILTER</b> hook with ThreadID==0.</li>
  </ul>
  If the call is successful, it returns the hook handle in eax. If not, NULL is 
  returned. You must save the hook handle for unhooking later.</blockquote>
You can uninstall a hook by calling<b> UnhookWindowsHookEx</b> which accepts only 
one parameter, the handle of the hook you want to uninstall. If the call succeeds, 
it returns a non-zero value in eax. Otherwise, it returns NULL. <br>
Now that you know how to install/uninstall hooks, we can examine the hook procedure. 
<br>
The hook procedure will be called whenever an event that is associated with the 
type of hook you have installed occurs. For example, if you install <b>WH_MOUSE</b> 
hook, when a mouse event occurs, your hook procedure will be called. Regardless 
of the type of hook you installed, the hook procedure always has the following 
prototype: 
<ul>
  <b>HookProc proto nCode:DWORD, wParam:DWORD, lParam:DWORD</b> <br>
  &nbsp; 
  <ul>
    <li> nCode specifies the hook code.</li>
    <li> wParam and lParam contain additional information about the event</li>
  </ul>
</ul>
HookProc is actually a placeholder for the function name. You can name it anything 
you like so long as it has the above prototype. The interpretation of nCode, wParam 
and lParam is dependent on the type of hook you install. So as the return value 
from the hook procedure. For example: 
<blockquote><b>WH_CALLWNDPROC</b> 
  <ul>
    <li> nCode can be only HC_ACTION which means there is a message sent to a 
      window</li>
    <li> wParam contains the message being sent, if it's not zero</li>
    <li> lParam points to a CWPSTRUCT structure</li>
    <li> return value: not used, return zero</li>
  </ul>
  <b>WH_MOUSE</b> 
  <ul>
    <li> nCode can be HC_ACTION or HC_NOREMOVE</li>
    <li> wParam contains the mouse message</li>
    <li> lParam points to a MOUSEHOOKSTRUCT structure</li>
    <li> return value: zero if the message should be processed. 1 if the message 
      should be discarded.</li>
  </ul>
</blockquote>
The bottom line is: you must consult your win32 api reference for details about 
the meanings of the parameters and return value of the hook you want to install. 
<br>
Now there is a little catch about the hook procedure. Remember that the hooks 
are chained in a linked list with the most recently installed hook at the head 
of the list. When an event occurs, Windows will call only the first hook in the 
chain. It's your hook procedure's responsibility to call the next hook in the 
chain. You can choose not to call the next hook but you'd better know what you're 
doing. Most of the time, it's a good practice to call the next procedure so other 
hooks can have a shot at the event. You can call the next hook by calling <b>CallNextHookEx</b> 
which has the following prototype: 
<blockquote><b>CallNextHookEx proto hHook:DWORD, nCode:DWORD, wParam:DWORD, lParam:DWORD</b> 
  <ul>
    <li> hHook is your own hook handle. The function uses this handle to traverse 
      the linked list and search for the hook procedure it should call next.</li>
    <li> nCode, wParam and lParam&nbsp; you can just pass those three values you 
      receive from Windows to CallNextHookEx.</li>
  </ul>
</blockquote>
An important note about remote hooks: the hook procedure must reside in a DLL 
which will be mapped into other processes. When Windows maps the DLL into other 
processes, it will not map the data section(s) into the other processes. In short, 
all processes share a single copy of code but they will have their own private 
copy of the DLL's data section! This can be a big surprise to the unwary. You 
may think that when you store a value into a variable in the data section of a 
DLL, that value will be shared among all processes that load the DLL into their 
process address space. It's simply not true. In normal situation, this behavior 
is desirable since it provides the illusion that each process has its own copy 
of the DLL. But not when Windows hook is concerned. We want the DLL to be identical 
in all processes, including the data. The solution: you must mark the data section 
as shared. You can do this by specifying the section(s) attribute in the linker 
switch. For MASM, you need to use this switch: 
<blockquote><b>/SECTION:&lt;section name>, S</b></blockquote>
The name of the initialized data section is .data and the uninitialized data is 
.bss. For example if you want to assemble a DLL which contains a hook procedure 
and you want the uninitialized data section to be shared amoung processes, you 
must use the following line: 
<blockquote><b>link /section:.bss,S&nbsp; /DLL&nbsp; /SUBSYSTEM:WINDOWS ..........</b></blockquote>
S attribute marks the section as shared. 
<h3> Example:</h3>
There are two modules: one is the main program which will do the GUI part and 
the other is the DLL that will install/uninstall the hook. 
<p>;--------------------------------------------- This is the source code of the 
  main program -------------------------------------- <br>
  <b>.386</b> <br>
  <b>.model flat,stdcall</b> <br>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -