III.1. Giới thiệu
Các mô hình Hook :
- Local hook: là kỹ thuật Hook dùng để bẫy sự kiện ngay trong tiến trình cài
đặt.
- Remote hook: là kỹ thuật Hook cho phép bẫy các sự kiện thuộc tiến trình
của ứng dụng khác. Trong mô hình này lại tồn tại hai kiểu hook khác :
+ Thread-specific : kiểu Hook này sẽ bẫy sự kiện của một luồng cụ thể.
+ System-wide : bẫy sự kiện của tất cả các luồng trong tất cả các tiến trình đang thi hành trong hệ thống.
Thành phần của Hook
- Chuỗi Hook - Thủ tục Hook - Các kiểu Hook
Hook là một kỹ thuật xử lý thông điệp rất mạnh cho phép chúng ta can thiệp sâu vào các tiến trình khác nhau, nhưng nó làm ảnh hưởng tới tốc độ của hệ thống, nhất là hook system-wide, vì tất cả các sự kiện của hệ thống sẽ được định hướng tới một hàm nào đó, rõ ràng điều này làm hệ thống chậm đi đáng kể. Vì thế ta chỉ hên hook những thông điệp thật cần thiết và kết thúc việc hook ngay khi không dùng đến nữa.
III.2. Chuỗi Hook
Hệ thống có khả năng hỗ trợ nhiều kiểu hook khác nhau, mỗi kiểu lại được quy định một cách thức truy nhập khác nhau trong kỹ thuật điều khiển thông điệp. Do vậy, hệ thống duy trì một chuỗi các hook cho mỗi một kiểu hook khác nhau.
Một chuỗi hook là một danh sách các con trỏ đặc biệt, nó được trỏ tới các hàm CallBack gọi là hook procedure (thủ tục hook). Như vậy khi một sự kiện xuất hiện, hệ thống sẽ chuyển sự kiện đó tới các thủ tục hook được tham chiếu bới chuỗi hook theo thứ tự lần lượt. Vì thế phải thực hiện xong thủ tục này mới được gọi thủ tục kế tiếp.
III.2.1. Thủ tục Hook
Thủ tục hook sẽ là nơi thực hiện các thao tác sau khi bắt được một sự kiện mong muốn. Các thủ tục hook phụ thuộc vào các kiểu hook khác nhau mà có cấu trúc, chức năng khác nhau. Có thủ tục chỉ có thể điều khiển thông điệp, một số khác có thể sửa đổi thông điệp, dừng tiến trình của thông điệp, ngăn cản thực hiện hook tiếp theo hoặc đưa tới cửa sổ cuối cùng …
Thủ tục hook có dạng chung như sau:
LRESULT CALLBACK HookProc( int nCode, WPARAM wParam, LPARAM lParam );
Trong đó :
- HookProc: là tên đại diện của thủ tục hook được cài đặt
- nCode : Đây là mã hook, nó quyết định toàn bộ hoạt động của thủ tục hook, mã hook phụ thuộc vào kiểu hook và mỗi kiểu hook được gán cho một ký tự để thiết lập mã hook.
- wParam, lParam: Hai tham số này chứa các thông tin về thông điệp được hook và nó phụ thuộc vào mã hook (nCode).
III.2.2. Các kiểu Hook
Mỗi một kiểu Hook cho phép ứng dụng điều khiển thông điệp theo những cách khác nhau trong kỹ thuật điều khiển thông điệp (message-handling mechanism). Dưới đây là những kiểu hook khác nhau :
- WH_CALLWNDPROC: Cài đặt một thủ tục hook theo dõi message trước
khi hệ thống sẽ gửi chúng đến các thủ tục cửa sổ đích.
- WH_CALLWNDPROCRET: Cài đặt một thủ tục hook theo dõi message
sau khi đã được xử lý bởi các thủ tục cửa sổ đích.
- WH_CBT: Cài đặt một thủ tục hook tiếp nhận thông báo hữu ích để một ứng dụng CBT.
- WH_DEBUG: Cài đặt một thủ tục hook hữu ích để gỡ lỗi thủ tục hook
khác.
- WH_FOREGROUNDIDLE: Cài đặt một thủ tục hook sẽ được gọi khi
luồng của ứng dụng là trở thành nhàn rỗi. Hook này rất hữu dụng cho thực hiện nhiệm vụ ưu tiên thấp trong thời gian nhàn rỗi.
- WH_GETMESSAGE: Cài đặt một thủ tục hook theo dõi các message
được đưa lên một hàng đợi message.
- WH_JOURNALPLAYBACK: Cài đặt một thủ tục hook gởi message
trước đây được ghi lại bằng một thủ tục hook WH_JOURNALRECORD.
- WH_JOURNALRECORD: Cài đặt một thủ tục hook ghi lại các message
đầu vào được đưa lên hàng đợi thông điệp hệ thống. Hook này rất hữu ích cho các macro ghi.
- WH_KEYBOARD: Cài đặt một thủ tục móc theo dõi tin nhắn tổ hợp
phím.
- WH_KEYBOARD_LL: Cài đặt một thủ tục móc theo dõi các sự kiện bàn
phím đầu vào ở mức độ thấp.
- WH_MOUSE: Cài đặt một thủ tục móc theo dõi tin nhắn chuột.
- WH_MOUSE_LL: Cài đặt một thủ tục móc theo dõi các sự kiện chuột đầu
vào ở mức độ thấp.
- WH_MSGFILTER: Cài đặt một thủ tục móc theo dõi tin nhắn được tạo ra
như là kết quả của một sự kiện đầu vào trong hộp thoại, hộp thông báo, menu, hoặc di chuyển một thanh.
- WH_SHELL: Cài đặt một thủ tục hook tiếp nhận thông báo hữu ích cho
các ứng dụng shell.
- WH_SYSMSGFILTER: Cài đặt một thủ tục móc theo dõi tin nhắn được
tạo ra như là kết quả của một sự kiện đầu vào trong hộp thoại, hộp thông báo, menu, hoặc di chuyển một thanh.
III.3. Cách sử dụng
III.3.1. Cài đặt Hook
Ta có thể cài đặt thủ tục hook vào chuỗi hook bằng việc gọi hàm
SetWindowsHookEx và chỉ ra kiểu hook đang gọi thủ tục, việc cài đặt hook có thể
thực hiện trên mọi tiến trình trong hệ thống.
Nếu sử dụng hook toàn cục thì phải đặt trong thư viện liên kết động (DLL). Ứng dụng muốn sử dụng thư viện liên kết động phải lấy được handle của thư viện đó. Để nhận Handle của thư viện liên kết động ta có thể sử dụng hàm LoadLibrary với tham số là tên của thư viện. Sau khi có được Handle của DLL, ta sẽ lấy địa chỉ của thủ tục hook trong thư viện liên kết động thông qua hàm GetProcAddress. Sau khi đã có thủ tục hook, sử dụng hàm SetWindowsHookEx để cài đặt thủ tục hook vào trong chuỗi hook.
Ví dụ về sử dụng thư viện liên kết động :
HOOKPROC lpfSetAutoProtect;
static HINSTANCE hinstDLL;
static HHOOK hhookysMsg;
hinstDLL = LoadLibrary(( LPCTSTR ) "c:\\Windows\\ BrowserHook.dll"); lpfSetAutoProtect= (HOOKPROC)GetProcAddress(hinstDLL, "SetAutoProtect"); hhookysMsg= SetWindowsHookEx(WH_SYSMSGFILTER,
lpfSetAutoProtect,hinstDLL,0);
III.3.2. Giải phóng Hook
Như đã nói thì hook nên được bỏ đi nếu như không cần thiết nữa bằng cách
sử dụng hàm UnhookWindowsHookEx.
Với thread-specific hook, việc sử dụng hàm UnhookWindowsHookEx sẽ giải phóng thủ tục hook. Tuy nhiên với hook toàn tục (system-wide hook) thì hàm này không thể trả tự do cho hàm DLL. Việc gọi hàm LoadLibrary sẽ gọi trong ngữ cảnh của tất cả các tiến trình, tuy nhiên hàm FreeLibrary thì không thể thực hiện với các
tiến trình khác. Vì vậy, không có cách nào để giải phóng DLL. Hệ thống chỉ có thể giải phóng DLL khi tất cả các tiến trình liên kết tới DLL đó phải kết thúc hoặc gọi FreeLibrary.
Giải pháp đặt ra cho vấn đề này là xây dựng hàm cài đặt ngay trong thư viện DLL. Bằng việc liên kết tới DLL, ứng dụng có thể cài đặt hook. Và ngay trong DLL cũng phải có hàm giải phóng hook để giải phóng khi không cần đến nữa.