windows挂钩注入DLL---获取桌面上所有图标名称及位置

5 篇文章 0 订阅

(1)HHOOK是全局唯一的,可以跨进程使用

(2)当创建钩子指定的函数第一次执行的时候,会创建一个线程

(3)当一个线程调用GetMessage的时候会转换为GUI线程,会有一个对应的消息队列,可以通过这个消息队列来传递我们的指令

(4)往某一个指定线程发送消息用PostThreadMessage

(5)当卸载钩子的时候,要确保我们在钩子函数中创建的消息退出,因为卸载钩子会导致DLL卸载,然后如果线程没有结束,会导致违规访问。可以通过消息队列将我们创建的Id传给我们的线程,然后用OpenThread打开对应的句柄,然后调用WaitForSingleObject

(6)由于一个DLL被映射到不同地址空间会有写时复制,导致进程之间数据共享困难,可以通过共享段。

(7)在Realse模式下编译运行

该项目主要有一个exe和一个DLL,这个DLL中有设置钩子以及对应的钩子函数。

先看DISPLib.DLL的实现

DISPLib.h代码:

#pragma once

#define MSG_INJ_SAVE_OK 1232
#define MSG_INJ_OK		1233
#define MSG_INJ_SAVE	1234
#define MSG_INJ_EXIT	1235

#ifdef DISPLIBAPI
#define DISPLIBAPI extern "C" __declspec(dllexport)
#else
#define DISPLIBAPI extern "C" __declspec(dllimport)
#endif // DEBUG

DISPLIBAPI BOOL SetDIPSHook(DWORD dwThreadId);

DISPLib.cpp代码:

#include "pch.h"
#include <windowsx.h>
#include <CommCtrl.h>
#include <string>
#include <sstream>
#include <fstream>

#include "DIPSLib.h"

LRESULT WINAPI GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam);

DWORD WINAPI ThreadFunc(LPVOID);

void SaveListViewItemPosition(HWND hWndLV);

#pragma data_seg("Shared")
HHOOK g_hHook = NULL;
DWORD g_dwThreadIdDIPS = 0;
#pragma data_seg()

#pragma comment(linker,"/Section:Shared,rws")

HINSTANCE g_hInstDll = NULL;

BOOL APIENTRY DllMain(HMODULE hModule,
    DWORD  ul_reason_for_call,
    LPVOID lpReserved
)
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    {
        //保存当前地址空间中DLL的基址
        g_hInstDll = hModule;
        break;
    }
    case DLL_THREAD_ATTACH:
        break;
    case DLL_THREAD_DETACH:
        break;
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

BOOL WINAPI SetDIPSHook(DWORD dwThreadId)
{
    BOOL bOk = FALSE;

    if (dwThreadId > 0)
    {
        if (g_hHook != NULL)
            return FALSE;

        //记录当前的线程ID
        g_dwThreadIdDIPS = GetCurrentThreadId();

        //向远程线程设置挂钩
        g_hHook = SetWindowsHookEx(WH_GETMESSAGE, GetMsgProc, g_hInstDll, dwThreadId);

        bOk = (g_hHook != NULL);

        if (bOk)
        {
            bOk = PostThreadMessage(dwThreadId, WM_NULL, 0, 0);
        }
    }
    else
    {
        if (g_hHook == NULL)
            return FALSE;

        bOk = UnhookWindowsHookEx(g_hHook);
    }

    return bOk;
}

LRESULT WINAPI GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    static BOOL bCrearteThreadSuccess = TRUE;

    if (bCrearteThreadSuccess)
    {
        HANDLE hThreadHndle = CreateThread(NULL, 0, ThreadFunc, NULL, 0, NULL);
        if (hThreadHndle != NULL)
        {
            bCrearteThreadSuccess = FALSE;
            CloseHandle(hThreadHndle);
        }
    }
   
    return CallNextHookEx(g_hHook, nCode, wParam, lParam);
}

void SaveListViewItemPosition(HWND hWndLV)
{
    int nMaxItems = ListView_GetItemCount(hWndLV);
    
    std::wofstream outFile;
    outFile.open("D:/DesktopIconPosition.txt", std::ios::out);
    if (outFile.good())
    {
        outFile.imbue(std::locale("chs"));

        outFile << L"Item Count:" << nMaxItems << std::endl;

        for (int i = 0; i < nMaxItems; i++)
        {
            TCHAR szName[MAX_PATH] = { 0 };
            ListView_GetItemText(hWndLV, i, 0, szName, _countof(szName));

            POINT pt;
            ListView_GetItemPosition(hWndLV, i, &pt);

            outFile << szName << L": x =" << pt.x << L" | y =" << pt.y << std::endl;
        }

        outFile.close();
    }
}

DWORD WINAPI ThreadFunc(LPVOID)
{
    DWORD dwCurThreadId = GetCurrentThreadId();

    //个DISP发送一个消息,表明线程创建成功
    //如果目标线程还没有对应的消息队列,则发送失败
    while (!PostThreadMessage(g_dwThreadIdDIPS, MSG_INJ_OK, (WPARAM)dwCurThreadId, 0))
    {
        Sleep(1000);
    }

    MSG msg;
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        if (msg.message == MSG_INJ_SAVE)
        {
            if (msg.lParam)
            {
                SaveListViewItemPosition((HWND)msg.wParam);
                break;
            }
        }
    }
    return 0;
}

#include "pch.h"中就两行代码:

#define WIN32_LEAN_AND_MEAN             // 从 Windows 头文件中排除极少使用的内容
// Windows 头文件
#include <windows.h>

DISP.exe实现:

DISP.cpp代码:

#include "framework.h"
#include "..\\DISPLib\DIPSLib.h"
#include <windowsx.h>
#include <string>
#include <sstream>
#include <iostream>
#include <fstream>


int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);


    HWND hWndLV = GetFirstChild(GetFirstChild(FindWindow(TEXT("ProgMan"), NULL)));

    if (!IsWindow(hWndLV))
    {
        MessageBox(NULL, L"hWndLV is not Windows", L"Info", MB_OK);
        return 1;
    }

    if (!SetDIPSHook(GetWindowThreadProcessId(hWndLV, NULL)))
    {
        MessageBox(NULL, L"Set Hook Failure", L"Info", MB_OK);
        return 1;
    }
    DWORD dwInjThreadId = 0;

    MSG msg;
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        if (msg.message == MSG_INJ_OK)
        {
            dwInjThreadId = (DWORD)msg.wParam;
            while (!PostThreadMessage(dwInjThreadId, MSG_INJ_SAVE, (WPARAM)hWndLV, 1))
            {
                Sleep(1000);
            }
        }
        //这个确认逻辑可以不要,后面的WaitForSingleObject更加保险,但是考虑到OpenThread可能失败,加了这一个保险,虽然这个逻辑不能保证卸载钩子时线程肯定退出了,但是大部分是ok的
        else if(msg.message == MSG_INJ_SAVE_OK)
        {
            break;
        }
    }

    HANDLE hInjThreadHandle = OpenThread(THREAD_ALL_ACCESS, FALSE, dwInjThreadId);

    DWORD wRet = WaitForSingleObject(hInjThreadHandle,INFINITE);

    CloseHandle(hInjThreadHandle);
    
    BOOL bOk = SetDIPSHook(0);

    if (bOk && wRet == WAIT_OBJECT_0)
    {
        MessageBox(NULL, L"钩子正常卸载", L"Info", MB_OK);
    }
    return 0;
}

#include "framework.h"中的代码如下:

#include "targetver.h"
#define WIN32_LEAN_AND_MEAN             // 从 Windows 头文件中排除极少使用的内容
// Windows 头文件
#include <windows.h>
// C 运行时头文件
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值