概括
我正在创建一个简单的应用程序,它允许用户选择一个包含顶级窗口的进程。用户首先键入本机 DLL(不是托管 DLL)的路径。然后用户键入将在挂钩过程中调用的方法的名称。该方法不能返回值并且必须是无参数的。然后它们是一个用于挂钩的按钮。
问题
我能够检索执行挂钩的库的模块句柄。此外,我还能够获取用户想要使用的模块句柄库,其中包含他/她想要挂钩的方法。另外,我能够接收用户想要挂钩的方法等的程序地址。
换句话说,它们不在返回的无效句柄上。除了挂钩的手柄 (HHOOK)
但是 SetWindowsHookEx 返回一个 NULL HHOOK 并且 GetLastError 返回错误代码 126 (ERROR_NO_MOD_FOUND)。
关于为什么我得到 ERROR_MOD_NOT_FOUND 的可能理论
- 全局钩子的数量是有限制的,因为我在某个地方读到了一个在钩子时遇到同样错误的人。
- 我没有得到将执行挂钩的 DLL 的正确模块句柄。但是话又说回来,我尝试了许多不同的方法来获取库 HMODULE/HINSTANCE 但都失败并出现相同的错误。
WinHooker.cpp
#include "winhooker.h"
HMODULE GetCurrentModule()
{
HMODULE hModule = NULL;
GetModuleHandleEx(
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
(LPCTSTR)GetCurrentModule,
&hModule);
return hModule;
}
LRESULT (WINAPI hookProc)(int nCode, WPARAM wParam, LPARAM lParam);
void recievedCallback(WIN32Hooker* hooker);
WIN32Hooker* current;
WIN32Hooker::WIN32Hooker(HINSTANCE* hInstance, Callback callback)
{
if (!hInstance)
{
HMODULE hModule = GetCurrentModule();
hInstance = &hModule;
}
this->callback = callback;
this->hInstance = hInstance;
return;
}
void WIN32Hooker::Hook(DWORD threadToHook)
{
recievedCallback(this);
this->hhk = SetWindowsHookEx(WH_CALLWNDPROC, hookProc, *this->hInstance, threadToHook);
DWORD errorCode = GetLastError(); // 126 ERROR_MOD_NOT_FOUND
return;
}
void WIN32Hooker::NextHook(int nCode, WPARAM wParam, LPARAM lParam)
{
callback();
CallNextHookEx(this->hhk, nCode, wParam, lParam);
return;
}
void WIN32Hooker::Free()
{
UnhookWindowsHookEx(this->hhk);
return;
}
LRESULT (WINAPI hookProc)(int nCode, WPARAM wParam, LPARAM lParam)
{
current->NextHook(nCode, wParam, lParam);
return 0;
}
void recievedCallback(WIN32Hooker* hooker)
{
current = hooker;
}
extern "C" WIN32Hooker* hookerMalloc(HINSTANCE* hInstance, Callback callback)
{
return new WIN32Hooker(hInstance, callback);
}
测试.cpp
#include <Windows.h>
extern "C" void sendMessage(void)
{
MessageBox(NULL, L"Test", L"Test", MB_ICONINFORMATION);
}
主要代码
// Window Hooker Bytes.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include "Window Hooker Bytes.h"
#include "processes.h"
#include "button.h"
#include "edit.h"
#include "listbox.h"
#include "/Users/FatalisProgrammer/Documents/Visual Studio 2010/Projects/Window Hooker Bytes/WindowHookerLib/winhooker.h"
#define MAX_LOADSTRING 100
using namespace Processes;
using namespace Controls;
void Delete(); // Delete proto-type
void windowListCallback(map<HWND, wstring>* list); // Callback proto-type
// Global Variables:
HINSTANCE hInst; // current instance
TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
TCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
Button* hookButton;
Edit* dllPathEdit;
Edit* methodNameEdit;
ListBox* windowList;
ProcessEnumerator* processEnumerator;
map<HWND, wstring> mapList;
// Forward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: Place code here.
MSG msg;
HACCEL hAccelTable;
// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_WINDOWHOOKERBYTES, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WINDOWHOOKERBYTES));
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
// COMMENTS:
//
// This function and its usage are only necessary if you want this code
// to be compatible with Win32 systems prior to the 'RegisterClassEx'
// function that was added to Windows 95. It is important to call this function
// so that the application will get 'well formed' small icons associated
// with it.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WINDOWHOOKERBYTES));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_WINDOWHOOKERBYTES);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassEx(&wcex);
}
//
// FUNCTION: InitInstance(HINSTANCE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hInst = hInstance; // Store instance handle in our global variable
hWnd = CreateWindow(szWindowClass, szTitle, WS_MINIMIZEBOX | WS_CAPTION | WS_SYSMENU, CW_USEDEFAULT, 0, 800 / 2, 480 / 2, NULL, NULL, hInstance, NULL);
hookButton = new Button(hWnd, 120, L"Hook Method From DLL!", 5, (480 / 2) - 24 - 24 - 24 - 6, (800 / 2) - 15, 24);
hookButton->show(hInst);
dllPathEdit = new Edit(hWnd, 169, 5, 5, (800 / 2) - 15, 24);
dllPathEdit->show(hInst);
dllPathEdit->setWatermarkText(L"Enter Path Of A Native DLL.");
methodNameEdit = new Edit(hWnd, 256, 5, (5 * 2) + 24, (800 / 2) - 15, 24);
methodNameEdit->show(hInst);
methodNameEdit->setWatermarkText(L"Enter Method (Must Return Void And Be Parameterless)");
methodNameEdit->setFont(L"Times", 16);
dllPathEdit->setFont(L"Times", 16);
hookButton->setFont(L"Times", 16);
windowList = new ListBox(hWnd, 333, 5, (5 * 8) + 24, (800 / 2) - 15, (124 / 2) + 24);
windowList->show(hInst);
windowList->setFont(L"Times", 16);
hookButton->setUACShield();
if (!hWnd)
{
return FALSE;
}
processEnumerator = new ProcessEnumerator();
processEnumerator->enumerateProcesses(windowListCallback);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
//
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
if (wmId == hookButton->getID())
{
HMODULE libraryModule = LoadLibrary(L"WindowHookerLib.dll");
typedef WIN32Hooker* (*HookerMalloc)(HINSTANCE* hInstance, Callback callback);
HookerMalloc hookerMalloc = (HookerMalloc)GetProcAddress(libraryModule, "hookerMalloc");
DWORD errorCode = GetLastError();
HMODULE libraryToHookModule = LoadLibrary(dllPathEdit->getText());
if (!libraryToHookModule || !libraryModule)
{
MessageBox(hWnd, L"Error: Library That Contains The Method To Hook Or The WindowHookerLib.dll Does Not Exist!\nMake Sure WindowHookerLib.dll Is In The Current Working Directory!", L"Error In Application!", MB_ICONERROR);
}
else
{
typedef void (__stdcall *Method)(void);
char* methodName = new char[wcslen(methodNameEdit->getText()) * 2];
wcstombs(methodName, methodNameEdit->getText(), wcslen(methodNameEdit->getText()) * 2);
Method method = (Method)GetProcAddress(libraryToHookModule, methodName);
if (!hookerMalloc || !method)
{
MessageBox(hWnd, L"Error: The Method To Hook Does Not Exist Or The Method To Initiate The Hooker Is Not Available!", L"Error In Application", MB_ICONERROR);
}
else
{
WIN32Hooker* hooker = hookerMalloc(NULL, method);
DWORD pID;
int selectedItemIndex = windowList->getSelectedIndex();
vector<HWND> v;
for(map<HWND,wstring>::iterator it = mapList.begin(); it != mapList.end(); ++it)
{
v.push_back(it->first);
}
GetWindowThreadProcessId(v[selectedItemIndex], &pID);
if (pID >= 0)
{
hooker->Hook(pID);
}
else
{
MessageBox(hWnd, L"Error Could Not Retrieve Process ID!", L"Error In Application", MB_ICONERROR);
}
}
delete methodName;
}
}
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
Delete();
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
void Delete()
{
delete dllPathEdit;
delete hookButton;
delete methodNameEdit;
delete windowList;
processEnumerator->free();
delete processEnumerator;
return;
}
void windowListCallback(map<HWND, wstring>* list)
{
mapList = *list;
vector<wstring> v;
for(map<HWND,wstring>::iterator it = mapList.begin(); it != mapList.end(); ++it)
{
v.push_back(it->second);
}
for each(wstring item in v)
{
windowList->addItem(item);
}
return;
}
结论
任何帮助,将不胜感激。如果我做错了什么,请随时指出。这个项目是为了学习目的,所以告诉我需要修复什么,或者任何提示都会很棒。