Windows Practice_Dll&Hook_消息钩子

Dll

Dll就是我们通常所说的动态链接库(Dynamic Link Library),它和应用程序在本质是没有任何区别的,它也是一个可执行文件,它们都有相同的PE结构。
但是两者在应用上面还是有一些区别的,Dll一般作用exe应用程序的补充体,它是一个模块,用来被exe文件加载。
在Windows中有一部分exe文件也是能够被加载的,比如.oxc后缀的控件格式。

为什么大部分应用程序喜欢使Dll?
  • 扩展了应用程序的特性;
  • 简化了项目管理;
  • 节省内存(一份Dll在系统中只有一份,需要用到这个Dll的程序,通过分页机制映射到当前进程中);
  • 促进资源共享;
  • 促进本地化;
  • 解决各版本之间的差异。
Dll和应用程序共享同一个进程空间
  • 在Dll中分配的内存必须由Dll来进行释放;
  • 应用程序不会因为Dll的卸载而释放空间。
Dll入口函数
BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
        case DLL_PROCESS_ATTACH:// 被加载的时候
        // Dll的初始化
        case DLL_THREAD_ATTACH:// 当应用程序中有新线程启动的时候
        // 这个时间点非常重要,应用程序新启动的线程加载本Dll模块时才调用,一般是对于线程安全的设置
        case DLL_THREAD_DETACH:// 被卸载的时候
        case DLL_PROCESS_DETACH:// 某个线程终止的时候
        // Dll的销毁
            break;
    }
    return TRUE;
}
Dll导出函数

对于一个动态链接库来说,最重要的是它的导出函数,只有导出函数才能被调用它的应用程序来使用。导出函数的格式如下:

extern "C" bool _declspec(dllexport) OnHook();

键盘拦截器的实现

Dll的实现
#pragma once
// WindowsMsgHookDemo.h文件
typedef void(*pFunc)(char *str);

extern "C" bool _declspec(dllexport) OnHook();
extern "C" bool _declspec(dllexport) OnSetFunc(pFunc func);
extern "C" bool _declspec(dllexport) UnHook();
// WindowsHookDemo.cpp : 定义 DLL 应用程序的导出函数。
//

#include "stdafx.h"
#include "WindowsMsgHookDemo.h"
#include <tchar.h>
#include <cstdio>


extern HMODULE g_hModule;
HHOOK g_hHook = nullptr;
pFunc g_myFunc;


LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam)
{
    if (code == HC_ACTION)
    {
        char str[MAXBYTE] = { 0 };
        if (lParam & 0x80000000)
        {
            sprintf_s(str, "[%c] 键被抬起 - 键盘码 [%04d]\r\n", wParam, wParam);
        }
        else
        {
            sprintf_s(str, "[%c] 键被按下 - 键盘码 [%04d]\r\n", wParam, wParam);
        }

        g_myFunc(str);
    }

    return CallNextHookEx(g_hHook, code, wParam, lParam);
}

bool OnHook()
{
    bool bRet = true;
    if (g_hHook == nullptr)
    {
        g_hHook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, g_hModule, 0);
    }
    else
    {
        bRet = false;
    }

    return bRet;
}

bool OnSetFunc(pFunc func)
{
    g_myFunc = func;
    return true;
}

bool UnHook()
{
    bool bRet = true;
    if (g_hHook != nullptr)
    {
        UnhookWindowsHookEx(g_hHook);
        g_hHook = nullptr;
    }
    else
    {
        bRet = false;
    }

    return bRet;
}
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "stdafx.h"

HMODULE g_hModule;

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        g_hModule = hModule;
        break;
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}
测试程序

将上面生成的WindowsHookDemo.dll放到测试程序中,能够被加载。

// DllTestDemo.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <Windows.h>

typedef void(*pFunc)(char *str);

typedef bool (*FUNC)(pFunc pfunc);

void myPrint(char *str)
{
    printf(str);
}

int main()
{
    HMODULE hDll = LoadLibrary(L"WindowsHookDemo.dll");
    FARPROC OnHook = GetProcAddress(hDll, "OnHook");
    FUNC OnSetFunc = (FUNC)GetProcAddress(hDll, "OnSetFunc");
    FARPROC UnHook = GetProcAddress(hDll, "UnHook");

    OnSetFunc(myPrint);
    OnHook();
    printf("OnHook()......\r\n");

    BOOL ret;
    MSG msg;
    while ((ret = GetMessage(&msg, nullptr, 0, 0)))
    {
        if (ret == -1)
            break;
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    UnHook();
    printf("UnHook()......\r\n");

    return 0;
}

运行测试程序,就会将所有的键盘输入信息打印到控制台上面。

注意事项

这个键盘拦截器需要注意一个函数的使用:

HHOOK WINAPI SetWindowsHookEx(
  _In_ int       idHook,
  _In_ HOOKPROC  lpfn,
  _In_ HINSTANCE hMod,
  _In_ DWORD     dwThreadId
);

我们监控的是键盘,所以还需要一个键盘钩子的回调函数,定义如下:

LRESULT CALLBACK KeyboardProc(
  _In_ int    code,
  _In_ WPARAM wParam,
  _In_ LPARAM lParam
);

这个函数一定要注意的是:
Remarks
An application installs the hook procedure by specifying the WH_KEYBOARD hook type and a pointer to the hook procedure in a call to the SetWindowsHookEx function.
This hook may be called in the context of the thread that installed it. The call is made by sending a message to the thread that installed the hook. Therefore, the thread that installed the hook must have a message loop.
如果加载这个Dll的应用程序没有消息循环,那么就不能正常运行,达不到预期的效果。

像上面的测试Dll程序时,我们自己写的exe程序,肯定有源码,在调试情况下LoadLibrary的时候会自动的将Dll附加到exe程序中,但是有的时候我们并没有exe文件的源码,也就是无法调试exe程序,如果我们想调试被加载的我们的Dll程序,就需要使用vs给我们提供的附加到进程的功能,如下图所示:
这里写图片描述
这里写图片描述
这样就能够进入到Dll设置的断点中了,达到了调试的目的。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值