`
java-mans
  • 浏览: 11444285 次
文章分类
社区版块
存档分类
最新评论

《Windows核心编程》---动态链接库和钩子基础

 
阅读更多

动态链接库是应用程序的一个模块,这个模块用于导出一些函数和数据以供其他程序中的其他模块调用:

1)动态链接库是应用程序的一部分,是作为模块被进程加载到自己的空间地址中;

2)动态链接库在程序编译时并不会被插入到可执行文件中,在程序运行时这个库的代码才会调入内存,即“动态链接”;

3)若有多个程序用到同一个动态链接库,Windows在物理内存中只保留一份库的代码,仅通过分页机制将这份代码映射到不同的进程中;

动态链接库的扩展名一般是dll,但也可以是某些exe、各种控件(*.ocx)等。

动态链接库的入口点函数是DllMain函数,它仅供操作系统使用,Windows在库装载、卸载、进程中线程创建和结束时调用入口函数,以便动态链接库采取相应的动作;DllMain函数的框架结构为:

BOOL APIENTRY DllMain(HANDLE hModule, //本模块句柄

DWORD ul_reason_for_call, //调用的原因

LPVOID lpReserved) //没有被使用

{

switch(ul_reason_for_call)

{

case DLL_PROCESS_ATTACH: //动态链接库刚被映射到某个进程的地址空间

case DLL_THREAD_ATTACH: //应用程序创建了一个新的线程

case DLL_THREAD_DETACH: //应用程序某个线程正常终止

case DLL_PROCESS_DETACH: //动态链接库将被卸载

default:

break;

}

return TRUE;

}

hModule参数是本DLL模块的句柄,即本动态链接库模块的实例句柄,数值上是系统将DLL文件映象加载到进程的地址空间时使用的基地址。

注意:在动态链接库中,通过GetModuleHandle(NULL)语句得到的是主模块(即可执行文件映象)的基地址,而不是DLL文件映象的基地址。

DLL可以定义两种函数:导出函数和内部函数。导出函数可以被其他模块调用,也可以被定义这个函数的模块调用,而内部函数当然只能被定义这个函数的模块调用。

动态链接库的主要功能是向外导出函数,供进程中其他模块使用。一般会生成3个主要的文件:.dll文件就是动态链接库,.lib文件时供程序开发用的导入库,.h文件包含了导出函数的声明。

调用DLL中的导出函数有两种方法:

1)装载期间动态链接:必须使用.lib文件,它为系统提供了加载这个DLL和定位DLL中的导出函数所需的信息;(上述3个文件都要用到)

实例代码如下:

#include <windows.h>

#include "acedll.h"

//指明要链接到acedll.lib库,也可以不用#pragma

//直接将acedll.lib文件添加到工程中也是一样的

#pragma comment(lib, "acedll")

void main()

{

//像调用本地函数一样调用acedll.lib库中的导出函数Export(..)

Export("SEE YOU IN ANOTHER LIFE BROTHER!");

}

这种方法的缺点是:如果用户丢失了DLL文件,那么程序是永远也不能启动的了。因此,很多时候要采用运行期间动态链接的方法,以便决定DLL加载失败后如何处理。

2)运行期间动态加载:使用LoadLibraryLoadLibraryEx函数在运行期间加载这个DLLDLL被加载后,加载模块调用GetProcAddress函数取得DLL导出函数的地址,再通过该函数地址调用DLL中的函数。(只需要.dll文件就行)为了实现这个方法,一般需要在工程中建立一个DEF文件,用来指定要导出的函数:

EXPORTS

Export

表示此DLL库要向外导出Export函数。

实例代码如下:

#include <windows.h>

//声明函数原型

typedef void(*PFNEXPORT)(LPCTSTR);

int main(int argc, char* argv[])

{

//加载DLL

HMODULE hModule = ::LoadLibrary("acedll.dll");

if(hModule != NULL)

{

//取得Export函数的地址

PFNEXPORT mExport = (PFNEXPORT)::GetProcAddress(hModule, "Export");

if(mExport != NULL)

{

mExport("SEE YOU IN ANOTHER LIFE BROTHER!");

}

//卸载DLL

::FreeLibrary(hModule);

}

return 0;

}

LoadLibrary函数的作用是加载指定目录下的DLL库到进程的虚拟地址空间,函数执行成功返回此DLL模块的句柄,否则返回NULL。事实上,载入器也是调用这个函数加载DLL的。

=====================JIN的分割线===================

Windows应用程序的运行模式是基于消息驱动的,任何线程只要注册了窗口类,都会有一个消息队列来接收用户的输入消息和系统消息。而为了取得特定线程接收或发送的消息,就要用到Windows提供的钩子。

钩子是Windows消息处理机制的一个监视点,应用程序可以在这里安装一个钩子函数以监视指定窗口某种类型的消息,所监视的窗口可以是其他进程创建的。钩子函数通过调用相关的API函数,把它挂入系统,每当特定消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,这时钩子函数既可以加工处理该消息,也可以不作处理而继续传递该消息。


关于Windows钩子需要知道以下几点:

1)钩子是用来截获系统中的消息流的;

2)截获消息后,用来处理消息的子程序叫做钩子函数,它是应用程序自定义的一个函数,在安装钩子时要把这个函数的地址告知Windows

3)系统中同一时间可能有多个进程安装了钩子,多个钩子函数在一起组成钩子链;因此,在处理截获到的消息后,应该把消息事件传递下去。

系统为每一种钩子建立一个钩子链(HOOK CHAIN),一个钩子链实际上就是一个指针列表,其指针指向钩子的各个处理函数,这些函数是一种特殊的回调函数。像堆栈一样,在钩子链中最后安装的钩子函数放在钩子链的最顶层,最先安装的钩子则放在钩子链的最底层,Windows系统负责记录和管理这条函数链。系统的各种消息首先被送到最顶层的钩子函数,即最后加入的钩子优先获得控制权。


钩子按事件分类主要有以下几种类型:

1)键盘钩子和低级键盘钩子:监视各种键盘消息;

2)外壳钩子:监视各种Shell事件消息,如启动和关闭应用程序等;

3)鼠标钩子和低级鼠标钩子:监视各种鼠标消息;

4)窗口过程钩子:监视所有从系统消息队列发往目标窗口的消息;

5)日志钩子:即如从系统消息队列中取出的各种事件消息。

安装钩子:

SetWindowsHookEx函数可以把应用程序定义的钩子函数安装到系统中:

HHOOK SetWindowsHookEx(

int idHook, //指定钩子的类型ª

HOOKPROC lpfn, //钩子函数的地址。如果使º用的是远程钩子,钩子函数必须放在一个DLL

HINSTANCE hMod, //钩子函数所在DLL的实例句柄。如果是一个局部的钩子,该参数的值为NULL

DWORD dwThreadId); //指定要为哪个线程安装钩子,如果该值为0,那么该钩子将被解释为系统范围的

各个参数解释如下:

idHook参数取值:

WH_CALLWNDPROC:当目标线程调用SendMessage函数发送消息时,钩子函数被调用

WH_CALLWNDPROCRET:当SendMessage发送的消息返回时,钩子函数被调用

WH_GETMESSAGE:当目标线程调用GetMessagePeekMessage时,钩子函数被调用

WH_KEYBOARD:当从消息队列中查询WM_KEYUPWM_KEYDOWN消息时

WH_MOUSE:当调用从消息队列中查询鼠标事件消息时

WH_MSGFILTER:当对话框、菜单或滚动条要处理一个消息时,钩子函数被调用。该钩子是局部的,它是为那些有自己消息处理过程的控件对象设计的

WH_SYSMSGFILTER:和WH_MSGFILTER一样,只不过是系统范围的

WH_JOURNALRECORD:当windows从硬件队列中获得消息时

WH_JOURNALPLAYBACK:当一个事件从系统的硬件队列中被请求时

WH_SHELL:当关于Windows外壳事件发生时,譬如任务条需要重画它的按钮

WH_CBT:当基于计算机的训练(CBT)事件发生时

WH_FOREGROUNDIDLEWindows自己使用

WH_DEBUG:用来给钩子函数除错

如果dwThreadId参数是0,或者指定一个有其他进程创建的线程ID,则lpfn参数指向的钩子函数必须位于一个DLL中,因为进程的地址空间是相互隔离的,发生事件的进程不能调用其他进程地址空间的钩子函数。如果钩子函数的实现代码在DLL中,在相关事件发生时,系统会把这个DLL插入到发生事件的进程的地址空间,使它能够调用钩子函数。这种需要将钩子函数写进DLL以便挂钩其他进程事件的钩子称为远程钩子。

如果dwThreadId参数指定一个由自身进程创建的线程IDlpfn参数指向的钩子函数只要在当前进程中即可,不必非要写入DLL。这种仅挂钩属于自身进程事件的钩子称为局部钩子。

钩子函数的一般形式如下:

LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam)

{

//处理该消息的代码

.......

return ::CallNextHookEx(hHook, nCode, wParam, lParam);

}

其中,nCode参数是Hook代码,钩子函数用这个参数来确定任务,它的值依赖于Hook的类型。wParamlParam参数的值依赖于Hook代码,但是它们典型的值是一些关于发送或者接收消息的信息。

hHook参数是安装钩子时得到的钩子句柄(SetWindowsHookEx的返回值)。

卸载钩子:

BOOL UnhookWindowsHookEx(HHOOK hhk); //hhk是要卸载的钩子的句柄

下面实现右键双击关闭当前窗口的功能,为了使用方便,我们设计成没有界面的,因此,我们先用VC生成基于对话框的应用程序,并且在OnInitDialog()函数中添加如下实现程序无界面运行的代码:

SetWindowPos(&CWnd::wndNoTopMost, 0, 0, 0, 0, WSP_HIDEWINDOW);

ModifyStyleEx(WS_EX_APPWINDOW, WS_EX_TOOLWINDOW);

其中SetWindowPos函数完成了设置窗口处于最底层、大小为0并且隐藏的功能;ModifyStyleEx函数用来更改窗口的扩展样式。

为了完成全局钩子的安装,我们需要动态链接库ACEHook.dll,在SetHook()函数的实现中调用SetWindowsHookEx(WH_MOUSE, AceMouseProc, GetModuleHandle(ACEHook), 0)安装全局钩子,钩子函数AceMouseProc实现对鼠标右键双击事件的响应:

LRESULT CALLBACK AceMouseProc(

int nCode, WPARAM wParam, LPARAM lParam)

{

if(nCode >= 0)

{

if(wParam == WM_RBUTTONDBLCLK)

{

hWnd = GetForegroundWindow();

GetWindowRect(hWnd, &rt);

ptNew.x = rt.right - 13;

ptNew.y = rt.top + 13;

GetCursorPos(&ptOld);

SetCursorPos(ptNew.x, ptNew.y);

mouse_event(MOUSEEVENTF_LEFTDOWN, ptNew.x, ptNew.y, 0, 0);

mouse_event(MOUSEEVENTF_LEFTUP, PTNew.x, ptNew.y, 0, 0);

SetCursorPos(ptOld.x, ptOld.y);

return 1;

}

}

return CallNextHookEx(g_hMouse, nCode, wParam, lParam);

}

如果是右键双击事件,系统首先调用GetForegroundWindow()函数获得用户当前正在工作的窗口句柄,通过此窗口句柄可调用GetWindowRect()函数来获得当前工作窗口在屏幕上的坐标。ptNewPOINT类型变量,通过计算出的当前窗口的关闭按钮在屏幕上的坐标对其赋值。当前窗口的关闭按钮能响应鼠标事件的屏幕坐标范围是:[rt.right-4, rt.right-21],在此我们选用rt.right-13

窗口的关闭我们通过调用mouse_event()函数来完成,mouse_event()函数可以模拟鼠标按键及滚轮等动作,因此,通过在窗口关闭按钮位置合成鼠标的左键单击事件可以实现关闭窗口的功能。鼠标的左键单击事件通过组合左键按下(MOUSEEVENTF_LEFTDOWN)和左键放开(MOUSEEVENTF_LEFTUP)事件获得。

分享到:
评论

相关推荐

    多个钩子教程,动态链接库

    多个钩子教程,动态链接库,适合初学者多个钩子教程,动态链接库,适合初学者

    WINDOWS.核心编程第五版_windows核心编程_

    windows核心编程: 详细介绍window编程核心, 已经工程配置, 钩子等。

    VC++动态链接库(DLL)编程(pdf格式)

    此资料是我学习win动态链接库和Hoot技术编程时,从网上收集的资料,均为pdf格式,对我来说帮助不小,现发出来,希望对初学vc++动态链接库和钩子(Hook)的朋友有些帮助,有兴趣的朋友可以下来看看!~

    Windows消息处理机制--钩子实例

    钩子(Hook),是Windows消息处理机制的一个平台,应用程序可以在上面设置子程以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程所创建的。当消息到达后,在目标窗口处理函数之前处理它。钩子机制允许应用程序...

    windows钩子编程大全

    分别是输入名称表(Import Name Table,INT)和输入地址表(Import Address Table,IAT)。 IMAGE_THUNK_DATA结构是个双字,在不同时刻有不同的含义,当双字最高位为1时,表示函数以 序号输入,低位就是函数序号。当双字...

    windows核心编程: 详细介绍window编程核心, 工程配置, 钩子等.zip

    windows核心编程: 详细介绍window编程核心, 工程配置, 钩子等

    windows 钩子编程

    介绍了钩子的基本用法,并有例子,附有源代码

    动态链接库高级应用 resource only dll

    这是一个动态链接库高级应用实例,一共是3个工程.(包含全部源代码) 第一个工程:纯声音资源动态链接库的生成 第二个工程:全局钩子动态链接库的生成 第三个工程:调用前两个工程生成的动态链接库生成一个全局发声工程

    键盘钩子毕业论文

    1.Windows消息处理机制。 2.钩子函数的分类、使用、...3.Windows动态链接库的运行机制和使用方法。 4.SOCKET编程原理。 5.VC++ MFC编程基础。 6.Andorid应用开发。 7. 计算机信息安全管理与防范意思的部分内容。

    屏颜色拾取器-api-全局钩子-鼠标钩子-源码

    屏幕颜色拾取器-api-全局钩子-鼠标钩子-源码 拉动颜色框进行调节。并且修改RGB参数可以得到想要的色值。。 鼠标左键在颜色框上按下。然后移动到想到的色值区域就放开鼠标就可以了

    VC2010用动态链接库实现键盘钩子

    这是一个用VC2010编写的动态链接库程序

    键盘钩子-windows消息机制-抓取用户按下的每一个按键

    用于抓取用户输入的键盘消息,已封装好类。无反钩子功能

    windows钩子

    有关windows钩子的工程文件,包括实现全局windows钩子的dll工程和windows钩子的应用实例工程两部分,windows钩子工程同时实现了鼠标和键盘钩子,本工程可以作为windows钩子应用的框架,加以改造后就可以实现不同的...

    CppWindowsHook-C++windows钩子 例子

    C++windows钩子 例子C++windows钩子 例子C++windows钩子 例子C++windows钩子 例子

    Windows钩子教程

    windows钩子入门教程,适合新手。 来源:一路采撷 Blog:http://blog.csdn.net/MaybeHelios/

    windows下svn的pre-commit钩子

    用法:将本bat文件(不可改名)存在svn服务器端安装目录\仓库名\hooks下(该目录下有多个*.tmpl文件,包括pre-commit.tmpl即linux下的提交钩子,而pre-commit.bat为windows下的提交钩子),并修改文件中相应目录(共...

    python-钩子函数-通俗.docx

    python 钩子函数 通俗 Python钩子函数是一种非常有用的编程技术,它可以让程序员在特定的事件发生时执行特定的代码。这种技术在很多应用程序中都得到了广泛的应用,比如GUI应用程序、Web应用程序等等。 Python钩子...

    MFC 钩子编程 源代码

    MFC 钩子 编程 出于名师的上课例子,对于设计具有很好的参考价值

    WINDOWS钩子函数的使用方法

    WINDOWS钩子函数的使用方法, 基于线程的 它将捕获其它进程中某一特定线程的事件。简言之,就是可以用来观察其它进程中的某一特定线程将发生的事件。 系统范围的 将捕捉系统中所有进程将发生的事件消息

    08 钩子编程.ppt

    钩子编程 钩子编程 钩子编程 钩子编程 钩子编程 钩子编程 钩子编程 钩子编程 钩子编程 钩子编程 钩子编程 钩子编程 钩子编程 钩子编程 钩子编程 钩子编程 钩子编程 钩子编程 钩子编程 钩子编程 钩子编程 钩子编程 ...

Global site tag (gtag.js) - Google Analytics