如何使用SetWindowsHookEx和WH_KEYBOARD钩取外部进程

6
我试图钩取例如记事本的应用程序,但没有成功。全局钩子似乎可以正常工作。
在XP SP2上测试。
编辑:修改后的代码现在可以工作了。
我的DLL代码
#include <windows.h>
#include <iostream>
#include <stdio.h>

HINSTANCE hinst;
#pragma data_seg(".shared")
HHOOK hhk;
#pragma data_seg()
//#pragma comment(linker, "/SECTION:.shared,RWS") compiler error in VC++ 2008 express

LRESULT CALLBACK wireKeyboardProc(int code, WPARAM wParam,LPARAM lParam) {  
    if (code < 0) {
        return CallNextHookEx(0, code, wParam, lParam);
    }
    Beep(1000, 20);
    return CallNextHookEx(hhk, code, wParam, lParam);
}

extern "C" __declspec(dllexport) void install(unsigned long threadID) { 
    hhk = SetWindowsHookEx(WH_KEYBOARD, wireKeyboardProc, hinst, threadID);
}
extern "C" __declspec(dllexport) void uninstall() {
    UnhookWindowsHookEx(hhk); 
}

BOOL WINAPI DllMain(__in HINSTANCE hinstDLL, __in  DWORD fdwReason, __in  LPVOID lpvReserved) {
    hinst = hinstDLL;
    return TRUE;
}

我的程序

#include <Windows.h>

unsigned long GetTargetThreadIdFromWindow(char *className, char *windowName)
{
    HWND targetWnd;
    HANDLE hProcess;
    unsigned long processID = 0;

    targetWnd = FindWindow(className, windowName);
    return GetWindowThreadProcessId(targetWnd, &processID);
} 

int _tmain(int argc, _TCHAR* argv[]) {
    unsigned long threadID = GetTargetProcessIdFromWindow("Notepad", "Untitled - Notepad");
    printf("TID: %i", threadID);    

    HINSTANCE hinst = LoadLibrary(_T("MyDLL.dll")); 

    if (hinst) {
        typedef void (*Install)(unsigned long);
        typedef void (*Uninstall)();

        Install install = (Install) GetProcAddress(hinst, "install");
        Uninstall uninstall = (Uninstall) GetProcAddress(hinst, "uninstall");

        install(threadID);

        Sleep(20000);

        uninstall();
    }

    return 0;
}
1个回答

14

三个问题:

您在使用进程ID时应该使用线程ID。

您的HHOOK需要放入共享内存中:

#pragma data_seg(".shared")
HHOOK hhk = NULL;
#pragma data_seg()
#pragma comment(linker, "/SECTION:.shared,RWS")

您需要将您的HHOOK传递给CallNextHookEx

return CallNextHookEx( hhk, code, wParam, lParam);

1
GetWindowThreadProcessId() 返回你需要的线程 ID(作为其返回值)。使用内联汇编和 ReadProcessMemory 做任何事情都是不必要的,而且几乎肯定不起作用。 - RichieHindle
2
你还需要将 hhk 初始化为 0,否则它将无法正确共享。 - yoyoyoyosef
1
就此而言,自Windows 95以后的所有Windows版本都会忽略CallNextHookEx函数中的HHOOK参数;有关更多信息,请参见https://dev59.com/o3VC5IYBdhLWcg3wsTRi。 - Frerich Raabe
1
@Noitidart:必须在DLL中定义一个特定于线程的WH_MOUSE钩子,该钩子将被注入到接收鼠标事件的应用程序的上下文中调用。 WH_MOUSE_LL钩子不需要放在DLL中,但只能是系统范围内的。一种解决方案可能是使用WH_MOUSE_LL,然后使用WindowFromPoint()和GetWindowThreadProcessId()来忽略不属于目标线程的消息。 - RichieHindle
1
在您挂钩自己的线程的情况下,我不认为您需要 DLL,但我不能百分之百确定。如果您要挂钩同一进程中的不同线程,我也不知道。 - RichieHindle
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接