Tải bản đầy đủ (.doc) (7 trang)

Hướng dẫn về kỹ thuật hook

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (46.81 KB, 7 trang )

Có bao giờ các bạn đặt ra câu hỏi là tại sao chúng ta có thể gõ tiếng Việt
được trong Microsoft Word và các phần mềm soạn thảo văn bản khác hay
không? Rõ ràng là chúng ta không thể can thiệp vào mã của Microsoft Word
để sửa thành tiếng Việt khi chúng ta muốn soạn thảo văn bản tiếng Việt. Vậy
thì tại sao các phần mềm như VietKey, VNI-TanKy lại có thể làm được điều
này? Câu trả lời là sử dụng các Hook. Trong bài viết này, chúng ta sẽ cùng tìm
hiểu xem Hook là gì mà có thể làm được điều thần kỳ như vậy!
Truớc khi chúng ta tìm hiểu về Hook , chúng ta nhắc lại một chút về quá trình
xử lý thông điệp của hệ điều hành Windows
Quá trình xử lý thông điệp của Windows diễn ra như sau : Đầu tiên từ các
hành động của nguời dùng như là : click chuột, nhấn phím, .. thì hệ điều hành
sẽ chuyển các hành động tương ứng thành các thông điệp (message). Rồi sau
đó Windows đẩy các message này vào hàng đợi của hệ thống (system queue)
và từ system queue các message đuợc chuyển cho các hàng đợi của ứng dụng
(application queue). Từ lúc này các ứng dụng sẽ lấy các message này trong
hàng đợi ứng dụng của mình để xử lý (thông qua các vòng lặp chờ thông điệp
- message loop).
1. Hook là gì ?
Hook là cơ chế mà nhờ đó một hàm có thể chặn các sự kiện (message, mouse
actions, keystrokes ) trước khi chúng được gửi đến hàng đợi của ứng dụng.
Các hàm này có thể thực hiện một số thao tác trên sự kiện, và trong một vài
trường hợp có thể định nghĩa lại hoặc hủy bỏ sự kiện mà nó chặn được. Một
điểm quan trọng cần lưu ý là các hàm này được gọi bởi chính Windows chứ
không phải bởi ứng dụng của chúng ta.
Windows hỗ trợ nhiều loại hook khác nhau, mỗi loại nhắm đến việc chặn bắt
một loại thông điệp cụ thể nào đó. Ví dụ, một ứng dụng có thể sử dụng
WH_KEYBOARD để giám sát sự di chuyển của thông điệp bàn phím trong hệ
thống. Nhờ loại hook này mà một chương trình có thể can thiệp vào và tạo ra
khả năng gõ tiếng Việt khi soạn thảo văn bản. Một loại hook khác là
WH_MOUSE cho phép theo dõi các thông điệp liên quan đến hoạt động của
con chuột.



Hình trên mô tả quá trình xử lý thông điệp của Windows khi có sử dụng các
Hook .Thì như trên hình vẽ chúng ta có thể thấy rõ ràng rằng ,một khi chúng
ta sử dụng các Hook thì các Hook này sẽ được đặt nằm giữa System Queue và
Application Queue .


2. Cơ chế hoạt động của Hook
Hệ thống duy trì một chuỗi hook (hook chain) cho mỗi loại hook. Mỗi chuỗi
này là một danh sách liên kết các con trỏ đặt biệt, con trỏ này chính là các
hàm callback của ứng dụng có sẵn, nó còn được gọi là hàm hook (hàm lọc,
filter function)
Khi có một thông điệp được sinh ra thuộc một loại hook nào đó, nó sẽ được hệ
thống đẩy đi vào hàm hook đầu tiên trong chuỗi, lần lượt từng hàm một (qua
tất cả các hook trong chuỗi). Công việc của hàm hook có thể phức tạp hay
đơn giản tùy thuộc vào từng loại hook. Hàm hook cho một số loại chỉ có thể
giám sát, số khác có thể sửa đổi thông điệp hoặc dừng lại việc xử lý thông
điệp trên chuỗi hook trước khi chúng đến các hook tiếp theo hoặc đến cửa sổ
đích.
3. Ứng dụng của Hook
- Cho phép tạo ra các chương trình hỗ trợ gõ tiếng Việt như : Vietkey
- Cho phép tạo ra các chuơng trình Test tự động phần mềm (bằng cách phát
sinh các sự kiện phím, chuột giống như người dùng đang nhập vào).
- Cho phép thay đổi giao diện các ứng dụng đang chạy.
- Cho phép xem phần trợ giúp của các ứng dụng bằng việc nhấn một phím
nào đó, ví dụ như nhấn F1 chẳng hạn
- Và nhiều ứng dụng khác nữa tùy vào trí tưởng tượng của các bạn !…
4 . Cài đặt Hook
Giao diện lập trình ứng dụng (API) của Windows cung cấp 3 hàm để thao tác
với hook :

• SetWindowsHookEx
• UnhookWindowsHookEx
• CallNextHookEx
a) Cài đặt một Filter Function vào chuỗi các Filter Function của một hook
Tác vụ này được thực hiện thông qua hàm SetWindowsHookEx, khai báo của
hàm này như sau :
HHOOK SetWindowsHookEx( int idHook, HOOKPROC lpfn,
HINSTANCE hMod, DWORD dwThreadId);


Ý nghĩa của từng tham số :
idHook: Xác định loại hook mà ta muốn cài đặt, tham số này có thể là một
trong các giá trị sau :
• WH_CALLWNDPROC : đặt một thủ tục hook quản lý các thông điệp trước lúc
hệ thống gởi chúng tới cửa sổ đích.
• WH_CALLWNDPROCRET : đặt một thủ tục hook quản lý các thông điệp sau
khi chúng được xử lý bởi thủ tục cửa sổ đích.
• WH_CBT : đặt một thủ tục hook nhận những thông báo có ích tới ứng dụng
huấn luyện trên cơ sở tính toán (CBT).
• WH_DEBUG : đặt một thủ tục hook có ích cho việc debug những thủ tục
hook khác.
• WH_FOREGROUNDIDLE : đặt một thủ tục hook sẽ được gọi khi thread
foreground của ứng dụng sẽ trở thành không dùng đến. Hook này có ích cho
hoạt động những nhiệm vụ (task) độ ưu tiên thấp trong thời gian không được
dùng đến.
• WH_GETMESSAGE : đặt một thủ tục hook quản lý các thông điệp được post
tới hàng đợi thông điệp.
•WH_JOURNALPLAYBACK : đặt một thủ tục hook post những thông điệp được
ghi trước đó bởi thủ tục hook WH_JOURNALRECORD.
•WH_JOURNALRECORD : đặt một thủ tục hook ghi những thông điệp đầu vào

được post tới hàng thông điệp hệ thống. Hook này có ích cho việc ghi các
macro.
• WH_KEYBOARD : đặt một thủ tục hook quản lý các thông điệp keystroke.
• WH_MOUSE : đặt một thủ tục hook quản lý các thông điệp chuột.
• WH_MSGFILTER: đặt một thủ tục hook quản lý các thông điệp được kết sinh
như là một kết quả cuả sự kiện đầu vào ở trong dialog box, message box,
menu hay scroll bar.
• WH_SYSMSGFILTER : đặt một ứng dụng các thông điệp được kết sinh như là
kết quả của một sự kiện đầu vào ở trong dialog box, message box, menu hay
scroll bar. Thủ tục hook quản lý những thông điệp này cho tất cả các ứng
dụng trong hệ thống.


Mỗi giá trị trên xác định một loại hook mà ta muốn cài đặt, mỗi loại hook có
một ý nghĩa và tình huống sử dụng khác nhau.
lpfn : Địa chỉ của Filter Function mà ta muốn gắn với hook.
hMod : Handle của module chứa Filter Function. Nếu ta cài đặt một hook cục
bộ (nghĩa là sự thực thi của Filter Function chỉ ảnh hưởng đối với tiến trình cài
đặt hook), tham số này phải là NULL. Còn nếu chúng ta muốn có một hook
với phạm vi toàn hệ thống (tức là mọi tiến trình đang hiện hữu đều chịu ảnh
hưởng bởi Filter Function của chúng ta), tham số này sẽ là Handle của DLL
chứa Filter Function.
dwThreadID : Định danh của thread ứng với hook đang được cài đặt . Nếu
tham số này là một số khác 0, Filter Function được gắn với hook chỉ được gọi
trong ngữ cảnh của một thread xác định. Còn nếu dwThreadID = 0, Filter
Function sẽ có phạm vi toàn hệ thống, và dĩ nhiên, nó sẽ được gọi trong ngữ
cảnh của bất kỳ thread nào đang tồn tại trên HĐH. Có thể sử dụng hàm
GetCurrentThreadId để lấy được handle của thread muốn cài đặt hook.
Một hook có thể được sử dụng ở mức hệ thống, ở mức cục bộ, hoặc ở cả hai
mức vừa nêu. Bảng sau mô tả các loại hook cùng tầm ảnh hưởng của nó :

WH_CALLWNDPROC
Thread , Global
WH_CALLWNDPROCRET
Thread , Global
WH_CBT
Thread , Global
WH_DEBUG
Thread , Global
WH_FOREGROUNDIDLE
Thread , Global
WH_GETMESSAGE
Thread , Global
WH_JOURNALPLAYBACK
Global
WH_JOURNALRECORD
Global


WH_KEYBOARD
Thread , Global
WH_MOUSE
Thread , Global
WH_MSGFILTER
Thread , Global
WH_SYSMSGFILTER
Global
Với một loại hook xác định, hook cục bộ sẽ được gọi trước, sau đó là hook
toàn cục.
b) Gỡ bỏ một Filter Function ra khỏi chuỗi các Filter Function của một hook
Windows cung cấp hàm UnhookWindowsHookEx giúp chúng ta thực hiện việc

này. Khai báo của nó như sau :
BOOL UnhookWindowsHookEx( HHOOK hhk);
Tham số : hhook chỉ ra hàm hook được dỡ bỏ . Đây là giá trị được trả vể bởi
hàm SetWindowsHookEx khi hàm Hook được cài đặt.
Chú ý : Hàm UnhookWindowsHookEx phải được sử dụng trong sự kết hợp với
hàm SetWindowsHookEx.
c) Chi tiết về Filter Function
Filter Function là một hàm được gắn với loại hook mà chúng ta muốn cài đặt.
Hàm này được gọi bởi hệ điều hành Windows chứ không được gọi bởi ứng
dụng, đây cũng là lý do mà người ta thường gọi nó là “Callback Function”. Tuy
nhiên , để thống nhất về mặt thuật ngữ, từ nay về sau chúng ta vẫn gọi nó là
Filter Function.
Tất cả các Filter Function đều có dạng sau :
LRESULT CALLBACK FilterFunc(int nCode, WPARAM wParam, LPARAM
lParam);
Ở đây “FilterFunc” chỉ là tên hàm tượng trưng, khi cài đặt, Filter Function sẽ
có tên bất kỳ theo ý của người lập trình .
Ý nghĩa của từng tham số truyền cho hàm :


nCode : tham số này thường được gọi là “hook code”, Filter Function sử dụng
giá trị này để quyết định cách thức xử lý đối với sự kiện. Giá trị của hook code
tùy thuộc vào từng loại hook cụ thể, và mỗi loại hook sẽ có tập hợp những giá
trị hook code đặc trưng của riêng mình. Có một quy luật mà dường như các
Filter Function của mọi loại hook cần tuân thủ : Khi Windows truyền cho hàm
giá trị hook code âm, Filter Function không được xử lý sự kiện mà phải gọi
hàm CallNextHookEx với chính những tham số mà hệ điều hành truyền cho
nó. Sau đó, nó phải trả về giá trị được trả về bởi hàm CallNextHookEx.
wParam, lParam: Đây là những thông tin cần thiết cho Filter Function trong
quá trình xử lý sự kiện. Các giá trị này sẽ có ý nghĩa khác nhau tuỳ thuộc vào

từng loại hook. Ví dụ , Filter Function gắn với hook WH_KEYBOARD sẽ nhận
mã phím ảo (Virtual-Key Code) từ wParam, đồng thời có được từ lParam thông
tin mô tả trạng thái của bàn phím khi sự kiện gõ phím xảy ra.
d) Gọi Filter Function kế tiếp trong chuỗi các Filter Function
Khi một hook được cài đặt, Windows gọi hàm đầu tiên trong chuỗi các Filter
Function, và kể từ thời điểm này, trách nhiệm Windows không còn nữa. Filter
Function hiện hành phải đảm bảo với hệ thống là có được lời gọi đến hàm kế
tiếp trong chuỗi các Filter Function. Bởi lẽ, có thể có một ứng dụng khác cũng
cài đặt cùng loại hook để thi hành một số tác vụ nào đó, và nếu như ta không
cho Filter Function của ứng dụng này tham gia xử lý sự kiện, sẽ có vấn đề rắc
rối xảy ra. Vấn đề sẽ càng trở nên nghiêm trọng nếu ứng dụng này là một
chương trình thuộc hệ thống, và rõ ràng sẽ không có gì đảm bảo cho sự an
toàn của hệ thống chúng ta. Để giải quyết vấn đề trên, hãy sử dụng hàm
CallNextHookEx, khai báo của nó như sau :
LRESULT CallNextHookEx( HHOOK hhk, int nCode, WPARAM wParam, LPARAM
lParam );
hhk : là handle của hook hiện hành, giá trị này có thể lấy được từ hàm
SetWindowsHookEx khi cài đặt hook.
nCode : chỉ định hook code để gởi đến hook kế tiếp. Hàm xử lý hook dùng giá
trị này để chỉ định xử lý thông điệp được gởi từ hook như thế nào .
wParam: chỉ định 16 bits thông tin mở rộng của thông điệp.
lParam: chỉ định 32 bits thông tin mở rộng của thông điệp.
Giá trị trả về : giá trị trả về là kết quả của quá trình xử lý và tùy thuộc vào
thông số nCode
Trong một số tình huống, Filter Function hiện hành có thể không muốn


chuyển sự kiện cho Filter Function khác trong cùng một chuỗi. Lúc này, nếu
loại hook chúng ta đang cài đặt cho phép huỷ bỏ sự kiện, và Filter Function
của chúng ta cũng có cùng quyết định là hủy bỏ, nó sẽ không phải gọi hàm

CallNextHookEx.
5. Chương trình minh họa
Để hiểu rõ hơn về Hook ,các bạn có thể xem một ví dụ đơn giản về sử dụng
Hook. Trong ví dụ này chúng ta sẽ cài đặt một Hook ,cho phép đọc thông tin
về menu bar chuẩn của bất kỳ chương trình ứng dụng nào và lưu các thông
tin này thành một tập tin resource (để sau đó ta có thể dễ dàng sử dụng trong
chương trình của mình!)
Trong ví dụ này chúng ta sẽ sử dụng Hook WH_GETMESSAGE để chặn bắt các
thông điệp gửi đến hàng đợi thông điệp . Và khi chương trình của chúng ta bắt
được thông điệp WM_NCLBUTTONDOWN (thông điệp này đuợc phát sinh khi
chúng ta click chuột lện thanh tiêu đề của cửa sổ) , chương trình sẽ cho mở
hộp thoại Save As để cho nguời dùng chọn đường dẫn và đặt tên cho file
resource sẽ được tạo ra .Và lúc này chuơng trình sẽ lưu toàn bộ nội dung của
menubar xuống thành file resource mà chúng ta đã đặt tên.
* Trong ví dụ này vì ta muốn lấy thông tin về menu bar của tất cả ứng dụng
trên Windows nên ta phải sử dụng một tập tin .DLL để lập một Hook loại toàn
cục (còn các hook loại cục bộ chỉ cho phép chặn các thông điệp trong nội bộ
ứng dụng có cài đặt Hook mà thôi).



×