Ứng Dụng Cơ Chế Hook Để Xây Dựng Chương Trình Hỗ Trợ Gõ Tiếng Việt Trên Hệ Điều Hành Window 32 Bit

18 600 2
Ứng Dụng Cơ Chế Hook Để Xây Dựng Chương Trình Hỗ Trợ Gõ Tiếng Việt Trên Hệ Điều Hành Window 32 Bit

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

[Programming] Ứng dụng chế Hook - Phần Ứng dụng chế Hook để xây dựng chương trình hỗ trợ gõ Tiếng Việt Hệ Điều Hành Windows 32 Bit - Phần I.Sự kiện thông điệp HĐH Windows I.1.Giới thiệu Ngày nay, Windows có lẽ không xa lạ với người sử dụng PC Nhắc đến Windows, người ta thường nghĩ Hệ Điều Hành (HĐH) dễ sử dụng, đó, tương tác người dùng với ứng dụng với thành phần tiện ích Windows thông qua giao diện đồ họa (GUI), thao tác keyboard, mouse vô đơn giản Một câu hỏi đặt : “Các ứng dụng làm để phân loại, lưu giữ đáp lại tương tác cho người dùng ?” Đối với Windows vấn đề giải cách trọn vẹn : HĐH đưa chế thông điệp (message) với tập hợp cấu trúc liệu hàm API hỗ trợ ứng dụng việc giao tiếp với người dùng I.2.Hai loại hàng đợi thông điệp Windows Trước hết, ta cần phải biết làm HĐH Windows lưu trữ thông điệp Hai loại hàng đợi Windows phục vụ cho mục đích : + Hàng đợi hệ thống (The System Queue) + Hàng đợi thông điệp ứng dụng (Application Queue) Hàng đợi hệ thống (The System Queue) Windows có trình điều khiển thiết bị (Drivers) chịu trách nhiệm cho dịch vụ ngắt từ thiết bị phần cứng mouse keyboard Tại thời điểm ngắt phát sinh, Driver gọi điểm vào (hàm) đặc biệt USER.EXE để kiện vừa xảy Tất kiện mouse, keyboard lưu hàng đợi gọi hàng đợi hệ thống (The System Queue) Đây hàng đợi dùng chung cho toàn hệ thống , tiến trình chạy chia xẻ hàng đợi Nhiệm vụ độc ghi nhận lại kiện phần cứng (mouse actions, keystrokes) chúng xảy Hàng đợi thông điệp ứng dụng (Application Queue) Khi tiến trình khởi tạo, hàng đợi đại diện cho tạo ra, hàng đợi (đôi gọi hàng đợi tác vụ) dùng để chứa thông điệp gởi cho cửa sổ ứng dụng Những thông điệp thông điệp gởi cách tường minh hai hàm sau : + PostMessage + PostAppMessage (Lưu ý : Hàm PostQuitMessage không gởi thông điệp vào hàng đợi ứng dụng Ứng dụng dùng hai Primitive GetMessage PeekMessage doWindows cung cấp để khảo sát hàng đợi Hai hàm cho phép ứng dụng “Lấy message khỏi hàng đợi” để từ phân loại có “Trả lời” thích hợp với người dùng I.3.Bàn thêm GetMessage PeekMessage Bên HĐH Windows, GetMessage PeekMessage thi hành mã lệnh Điểm khác biệt hàm trường hợp message trả cho ứng dụng Trong trường hợp này, GetMessage đặt ứng dụng vào trạng thái “Sleep” PeekMessage trả ứng dụng giá trị NULL Ngay trước GetMessage PeekMessage trả message cho ứng dụng, hệ thống kiểm tra xem có tồn hook WH_GETMESSAGE hay không Nếu có “Filter Function” (thực chất hàm) ứng với hook cài đặt, hàm gọi “Filter Function” không gọi PeekMessage không tìm thấy message trả NULL PeekMessage với tùy chọn PM_NOREMOVE Theo mặc định, PeekMessage GetMessage lấy message khỏi hàng đợi message trả cho ứng dụng Tuy nhiên, có đôi lúc, ứng dụng muốn vào hàng đợi để kiểm tra tồn messsage mà không muốn gỡ bỏ Để làm điều này, chương trình ta gọi PeekMessage với tùy chọn PM_NOREMOVE, lúc PeekMessage trả message thường lệ không lấy khỏi hàng đợi.(Chi tiết GetMessage PeekMessage tham khảo Article “GetMessage and PeekMessage Internals” thư viện MSDN) II.Sự kiện bàn phím II.1.Mô hình chung Mỗi phím bàn phím hệ thống gắn với giá trị gọi mã quét (Scan Code), giá trị phụ thuộc thiết bị, tức giá trị lệ thuộc vào loại bàn phím cụ thể Khi người dùng gõ phím, có mã quét sinh : phím nhấn phím thả Trình điều khiển bàn phím (Keyboard Device Driver) thông dịch mã quét chuyển thành mã phím ảo (vitual-key code), giá trị độc lập thiết bị, định nghĩa hệ thống Sau đó, trình điều khiển tạo thông điệp bao gồm scancode, virtual-key code số thông tin khác (sự lặp phím, trạng thái phím Alt, Ctrl ) , đặt vào hàng đợi hệ thống Hệ thống lấy thông điệp khỏi hàng đợi hệ thống gởi đến hàng đợi thông điệp ứng dụng Cuối cùng, vòng lặp thông điệp (Message Loop) lấy thông điệp khỏi hàng đợi ứng dụng chuyển đến hàm xử lý message thích hợp để xử lý Quá trình minh hoạ qua hình vẽ sau : Rõ ràng ta có cách để có message trước đến hàm xử lý thông điệp cửa sổ, ta thực vài thao tác thú vị Và HĐH Windows, điều hoàn toàn thực nhờ chế hook ta thấy phần sau II.2.Các thông điệp liên quan bàn phím Khi ta nhấn phím, thông điệp WM_KEYDOWN đặt vào hàng đợi tiểu trình ứng với cửa sổ focus Và ta nhả phím, hàng đợi có thông điệp WM_KEYUP Hai thông điệp thường xuất thành cặp Tuy nhiên, ta nhấn phím giữ phím đủ lâu làm đặc tính “Automatic Repeat” bàn phím hoạt động, hệ thống sinh nhiều thông điệp WM_KEYDOWN liên tiếp Và lưu ý điều nhả phím, có thông điệp WM_KEYUP phát sinh mà wParam thông điệp cho ta mã phím ảo (virtual-key code) phím nhấn lParam dùng 32 bit để mô tả thông tin thêm kiện gõ phím tạo message Thông tin bao gồm : lặp phím, mã quét (scan code), trạn thái phím ALT, trạng thái phím trước, Sơ đồ 32 bit sau : Repeat Count : Hệ thống tăng đếm lên bàn phím phát sinh thông điệp WM_KEYDOWN nhanh khả xử lý message ứng dụng Điều thường xảy người dùng giữ phím đủ lâu làm cho đặc tính “Automatic Repeat” bàn phím hoạt động Lúc này, thay đặt vào hàng đợi hệ thống nhiều thông điệp WM_KEYDOWN liên tiếp, hệ thống kết hợp message thành message tăng giá trị Repeat Count Tác vụ nhả phím không làm cho đặc tính “Automatic Repeat” kích hoạt, giá trị Repeat Count thông điệp WM_KEYUP luôn Scan Code : Giá trị phụ thuộc thiết bị bàn phím phát sinh phím bị nhấn hay nhả Đây mã ký tự đại diện cho phím nhấn Ứng dụng thường không quan tâm đến giá trị này, thay vậy, sử dụng giá trị độc lập thiết bị mã phím ảo (virtual-key code) để xử lý message Extended-Key Flag Bit cờ hiệu cho biết phím có phải phím mở rộng hay không Bit bật phím bị nhấn phím mở rộng : INS, DEL, HOME, END, Context Code Bit cờ hiệu cho biết thời điểm thông điệp phát sinh, phím ALT có bị nhấn hay không Bit bật phím ALT bị nhấn, tắt phím ALT nhả Previous Key-State Flag Bit cờ hiệu cho biết trạng thái phím trước gởi message “up” hay “down” Bit phím “down”, phím “up” Transition-State Flag Bit WM_KEYDOWN, WM_KEYUP.Thông điệp WM_KEYDOWN, WM_KEYUP cung cấp cho ta nhiều thông tin kiện gõ phím, nhiên, không cho ta mã ký tự phím nhấn Để có thông tin này, ứng dụng phải thêm hàm TranslateMessage vào vòng lặp thông điệp mình.Hàm chuyển thông điệp WM_KEYDOWN thành thông điệp WM_CHAR chứa mã ký tự ứng với phím gõ, sau kiểm tra trạng thái phím SHIFT CAPS LOCK II.3.Giả lập gõ phím Đôi muốn có kiện gõ phím mà tác động mặt vật lý bàn phím Hàm keybd_event giúp ta có khả này, chức giả lập thao tác bàn phím (nhấn hay nhả) Khai báo hàm sau : VOID keybd_event( BYTE bVk, // virtual-key code BYTE bScan, // hardware scan code DWORD dwFlags, // function options ULONG_PTR dwExtraInfo // additional keystroke data ); Ý nghĩa tham số : bVk : mã phím ảo phím cần giả lập bScan : tham số không dùng dwFlags : xác định loại thao tác cần giả lập, tham số giá trị sau : Giá trị Ý nghĩa KEYEVENTF_EXTENDEDKEYScan Code trước giá trị 224 KEYEVENTF_KEYUP Giả lập thao tác nhả phím dwExtraInfo : thông tin thêm kiện ta giả lập III.Cơ chế Hook HĐH Windows III.1.Giới thiệu Trên HĐH Windows, hook chế mà nhờ hàm chặn kiện (message, mouse actions, keystrokes) trước chúng đến ứng dụng Hàm thực số thao tác kiện, vài trường hợp định nghĩa lại hủy bỏ kiện mà bắt Một đặc điểm quan trọng cần lưu ý hàm gọi thân HĐH Windows ứng dụng Các hàm thuộc loại vừa nêu thường gọi Filter Function, chúng phân loại theo loại kiện mà chúng can thiệp.Ví dụ, Filter Function hứng tất kiện mouse khác với Filter Function can thiệp kiện keyboard … Một Filter Funtion muốn Windows gọi trước tiên phải gắn với Windows Hook, công việc thường gọi “Cài đặt hook” Windows Hook thật loại hook khác HĐH định nghĩa, giúp người sử dụng cài đặt Filter Function với mục đích mà họ mong muốn Khi cài đặt hook, ta xác định loại hook thông qua số có dạng WH_XXX, ví dụ WH_KEYBOARD xác định loại hook dùng để can thiệp kiện thuộc bàn phím Một Windows Hook có nhiều Filter Function gắn với nó, tình này, Windows trì chuỗi Filter Function Hàm cài đặt gần đầu chuỗi, hàm cài đặt lâu cuối chuỗi Lúc này, có kiện xảy kiện tương ứng với loại hook ta cài đặt, Windows gọi hàm chuỗi Filter Function ứng với hook III.2.Khả ứng dụng chế Hook Hook cung cấp khả mạnh cho ứng dụng chạy Windows, ứng dụng dùng hook để : · Xử lý định nghĩa tất thông điệp cho dialog box, message box, scroll bar, menu ứng dụng (Sử dụng hook WH_MSGFILTER) · Xử lý định nghĩa tất thông điệp cho dialog box, message box, scroll bar, menu hệ thống (Sử dụng hook WH_SYSMSGFILTER) · Xử lý định nghĩa tất thông điệp (bất chấp thông điệp gì) hệ thống GetMessage PeekMessage gọi (Sử dụng hook WH_GETMESSAGE) · Xử lý định nghĩa tất thông điệp (bất chấp thông điệp gì) hệ thống SendMessage gọi (Sử dụng hook WH_CALLWNDPROC) · Thu (Record) phát lại (Playback) kiện keyboard mouse (Sử dụng hook WH_JOURNALRECORD, WH_JOURNALPLAYBACK) · Xử lý , định nghĩa hủy bỏ tất kiện bàn phím.(Sử dụng hook WH_KEYBOARD) · Xử lý , định nghĩa hủy bỏ tất kiện chuột (Sử dụng hook WH_MOUSE) Tận dụng khả trên, ứng dụng sử dụng hook để : · Cung cấp phím trợ giúp F1 hỗ trợ menu, dialog box message box (Sử dụng hook WH_MSGFILTER) · Cung cấp tính thu phát kiện mouse keyboard, thường gọi macro (Sử dụng hook WH_JOURNALRECORD, WH_JOURNALPLAYBACK) · Theo dõi thông điệp để biết thông điệp gởi đến cửa sổ hành động làm phát sinh thông điệp tương ứng (Sử dụng hook WH_GETMESSAGE & WH_CALLWNDPROC) Chương trình Spy Win32™ SDK Windows NT thành công việc sử dụng hook để thực tác vụ · Giả lặp tác vụ input keyboard mouse (Sử dụng hook WH_JOURNALPLAYBACK) Chỉ có hook cho ta phương pháp chắn tin cậy để thực điều Nếu ta tiếp cận theo cách khác, gởi message chẳng hạn, Windows không cập nhật trạng thái mouse keyboard, điều dẫn đến hành động không mong muốn Còn hook sử dụng, kiện xử lý y hệt kiện vật lý III.3.Quản lý chuỗi Filter Function Giao diện lập trình ứng dụng (API) Windows cung cấp hàm để thao tác với hook : · SetWindowsHookEx · UnhookWindowsHookEx · CallNextHookEx Cài đặt Filter Function vào chuỗi Filter Function hook Tác vụ thực thông qua hàm SetWindowsHookEx, khai báo hàm sau : HHOOK SetWindowsHookEx( int idHook, // hook type HOOKPROC lpfn, // hook procedure HINSTANCE hMod, // handle to application instance DWORD dwThreadId // thread identifier ); Ý nghĩa tham số : idHook : Xác định loại hook mà ta muốn cài đặt, tham số giá trị sau : · WH_CALLWNDPROC · WH_CALLWNDPROCRET · WH_CBT · WH_DEBUG · WH_FOREGROUNDIDLE · WH_GETMESSAGE · WH_JOURNALPLAYBACK · WH_JOURNALRECORD · WH_KEYBOARD · WH_MOUSE · WH_MSGFILTER · WH_SYSMSGFILTER Mỗi giá trị xác định loại hook mà ta muốn cài đặt, loại hook có ý nghĩa tình sử dụng khác nhau, chi tiết loại hook đề cập sau lpfn : Địa Filter Function mà ta muốn gắn với hook, hàm phải “export” macro thích hợp ta cài đặt hMod : Handle module chứa Filter Function Nếu ta cài đặt hook cục (nghĩa thực thi Filter Function ảnh hưởng tiến trình cài đặt hook), tham số phải NULL Còn ta muốn có hook với phạm vi toàn hệ thống (tức tiến trình hữu chịu ảnh hưởng Filter Function ta), tham số Handle DLL chứa Filter Function dwThreadID : Định danh thread ứng với hook cài đặt Nếu tham số số khác 0, Filter Function gắn với hook gọi ngữ cảnh thread xác định Còn dwThreadID = 0, Filter Function có phạm vi toàn hệ thống, dĩ nhiên, gọi ngữ cảnh thread tồn HĐH Có thể sử dụng hàm GetCurrentThreadId để lấy handle thread muốn cài đặt hook Một hook sử dụng mức hệ thống, mức cục bộ, hai mức vừa nêu Bảng sau mô tả loại hook tầm ảnh hưởng : 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_JOURNALPLAYBACKGlobal WH_JOURNALRECORD Global WH_KEYBOARD Thread , global WH_MOUSE Thread , global WH_MSGFILTER Thread , global WH_SYSMSGFILTER Global Với loại hook xác định, hook cục gọi trước, sau hook toàn cục SetWindowsHookEx trả handle hook cài đặt (là giá trị có kiểu HHOOK) Giá trị cần lưu lại để dùng hàm UnhookWindowsHookEx ta muốn gỡ bỏ hook Nó trả NULL gắn Filter Function vào hook, trường hợp này, gọi hàm GetLastError để biết lý cài đặt hook thất bại, giá trị mã lỗi giá trị sau :         ERROR_INVALID_HOOK_FILTER : số xác định loại hook sai ERROR_INVALID_FILTER_PROC : địa Filter Function không xác ERROR_HOOK_NEEDS_HMOD : tham số hMod hàm SetWindowsHookEx NULL ứng dụng muốn cài đặt hook toàn cục ERROR_GLOBAL_ONLY_HOOK : Ứng dụng cố cài đặt hook cục chất loại hook hook toàn cục ERROR_INVALID_PARAMETER : giá trị tham số dwThreadID không xác ERROR_JOURNAL_HOOK_SET : Đã có hook loại “Journal” (WH_JOURNALPLAYBACK WH_JOURNALRECORD) hữu hệ thống Vì lý an toàn, Windows cho phép ta cài đặt hook loại “Journal” thời điểm ERROR_MOD_NOT_FOUND : Ứng dụng định vị handle DLL muốn cài đặt hook toàn cục Các giá trị khác : Vấn đề an toàn HĐH không cho phép hook cài đặt, hệ thống hết nhớ Gỡ bỏ Filter Function khỏi chuỗi Filter Function hook Windows cung cấp hàm UnhookWindowsHookEx giúp ta thực việc này.Khai báo sau : BOOL UnhookWindowsHookEx( HHOOK hhk // handle to hook procedure ); Tham số hàm handle hook cần gỡ bỏ Giá trị giá trị trả từ hàm SetWindowsHookEx ta cài đặt hook Chi tiết Filter Function Đây thời điểm thích hợp để bàn Filter Function Nhắc lại Filter Function hàm gắn với loại hook mà ta muốn cài đặt Hàm gọi HĐH Windows không gọi ứng dụng, lý mà người ta thường gọi “Callback Function” Tuy nhiên , để thống mặt thuật ngữ, từ sau ta gọi Filter Function Tất Filter Function có dạng sau : LRESULT CALLBACK FilterFunc(int nCode, WPARAM wParam, LPARAM lParam); Lưu ý : “FilterFunc” tên hàm tượng trưng, cài đặt, Filter Function có tên theo ý lập trình viên · Ý nghĩa tham số truyền cho hàm nCode : tham số thường gọi “hook code”, Filter Function sử dụng giá trị để định cách thức xử lý kiện (Lưu ý điều hoàn toàn tuỳ thuộc vào lập trình viên Có thể hình dung hook code đem lại thông tin đó, từ thông tin này, lập trình viên định xử lý kiện bắt theo hướng riêng anh ta) Giá trị hook code tùy thuộc vào loại hook cụ thể, loại hook có tập hợp giá trị hook code đặc trưng riêng Có quy luật mà dường Filter Function loại hook cần tuân thủ : Khi Windows truyền cho hàm giá trị hook code âm, Filter Function không xử lý kiện mà phải gọi hàm CallNextHookEx với tham số mà HĐH truyền cho Sau đó, phải trả giá trị trả hàm CallNextHookEx wParam, lParam : Đây thông tin cần thiết cho Filter Function trình xử lý kiện Các giá trị có ý nghĩa khác tuỳ thuộc vào loại hook Ví dụ, Filter Function gắn với hook WH_KEYBOARD nhận mã phím ảo (Virtual-Key Code) từ wParam, đồng thời có từ lParam thông tin mô tả trạng thái bàn phím kiện gõ phím xảy · Gọi Filter Function chuỗi Filter Function Khi hook cài đặt, Windows gọi hàm chuỗi Filter Function, kể từ thời điểm này, trách nhiệm Windows không Filter Function hành phải đảm bảo với hệ thống có lời gọi đến hàm chuỗi Filter Function Bởi lẽ, có ứng dụng khác cài đặt loại hook để thi hành số tác vụ đó, ta không cho Filter Function ứng dụng tham gia xử lý kiện, có vấn đề rắc rối xảy Vấn đề trở nên nghiêm trọng ứng dụng chương trình thuộc hệ thống, rõ ràng đảm bảo cho an toàn hệ thống Để giải vấn đề trên, sử dụng hàm CallNextHookEx, khai báo sau : LRESULT CallNextHookEx( HHOOK hhk, // handle to current hook int nCode, // hook code passed to hook procedure WPARAM wParam, // value passed to hook procedure LPARAM lParam // value passed to hook procedure ); Tham số handle hook hành, giá trị lấy từ hàm SetWindowsHookEx cài đặt hook Ba tham số giá trị mà Windows truyền cho Filter Function.Trong số tình huống, Filter Function hành không muốn chuyển kiện cho Filter Function khác chuỗi Lúc này, loại hook ta cài đặt cho phép huỷ bỏ kiện, Filter Function ta có định hủy bỏ, gọi hàm CallNextHookEx Có thực tế mà lập trình viên buộc phải chấp nhận : họ biết vị trí Filter Function chuỗi Filter Function Bởi ta gọi hàm CallNextHookEx, Windows đối tượng định xem phải chọn hàm để bàn giao kiện, trình dĩ nhiên HĐH giấu kín Do đó, cách khôn ngoan (và bắt buộc) để đảm bảo an toàn hệ thống tuân thủ nguyên tắc HĐH cài đặt sử dụng hook Filter Function cho Hook toàn cục DLL Như có lần đề cập, ta muốn cài đặt hook toàn cục, Filter Function phải hàm nằm DLL (Dynamic Link Library) Tuy nhiên, có ngoại lệ ta cài đặt hai hook toàn cục WH_JOURNALRECORD WH_JOURNALPLAYBACK Bởi lẽ hai loại hook này, Windows gọi Filter Function theo cách đặc thù, nên hàm không cần phải nằm DLL III.4 Giới thiệu hook WH_KEYBOARD WH_GETMESSAGE Bây chi tiết Filter Function gắn với hook WH_KEYBOARD WH_GETMESSAGE, hai loại hook liên quan chọn để cài đặt Filter Function cho hook WH_KEYBOARD Windows gọi Filter Function hook GetMessage PeekMessage trả thông điệp WM_KEYDOWN, WM_KEYUP Prototype hàm có dạng sau : LRESULT CALLBACK KeyboardProc( int code, // hook code WPARAM wParam, // virtual-key code LPARAM lParam // keystroke-message information ); code : xác định cách thức Filter Function xử lý thông điệp, hai giá trị sau : Value HC_ACTION HC_NOREMOVE Meaning Thông điệp lấy khỏi hàng đợi, wParam lParam chứa thông tin thông điệp mà Filter Function nhận wParam lParam mang thông tin thông điệp, thông điệp nằm hàng đợi (Ứng dụng gọi PeekMessage với tuỳ chọn PM_NOREMOVE) Nếu code giá trị âm, Filter Function phải chuyển thông điệp cho Filter Function khác cách gọi CallNextHookEx, trả giá trị trả hàm CallNextHookEx wParam : chứa mã phím ảo phím nhấn lParam : thông tin khác kiện gõ phím, thông tin mô tả phần Filter Function cho hook WH_GETMESSAGE Như phần đầu giới thiệu, trước GetMessage PeekMessage trả thông điệp cho ứng dụng, thông điệp chuyển cho Filter Function hook để hàm thực số thao tác kiểm tra, chỉnh sửa thông tin message Tuy nhiên, Filter Function hủy bỏ thông điệp mà nhận Đây nguyên tắc sử dụng hook WH_GETMESSAGE Filter Function hook có dạng sau : LRESULT CALLBACK GetMsgProc( int code, // hook code WPARAM wParam, // removal option LPARAM lParam // message ); code : Filter Function sử dụng giá trị để định xem có phải xử lý message hay không Nếu code=HC_ACTION, Filter Function phải xử lý thông điệp Nếu code giá trị âm, Filter Function phải chuyển message cho hàm khác cách gọi CallNextHookEx mà thay đổi thông điệp Sau đó, phải trả giá trị trả hàm CallNextHookEx wParam : giá trị tham số cho ta biết message mà Filter Function nhận có lấy khỏi hàng đợi hay chưa Nó giá trị sau Giá trị PM_NOREMOVE PM_REMOVE Ý nghĩa Message nằm hàng đợi, điều đồng nghĩa với việc ứng dụng gọi PeekMessege với tuỳ chọn PM_NOREMOVE Message lấy khỏi hàng đợi, ứng dụng gọi GetMessage, PeekMessage với tuỳ chọn PM_REMOVE lParam : trỏ đến cấu trúc MSG chứa thông tin chi tiết message IV.Cài đặt sử dụng hook toàn cục Phần nêu vắn tắt cách cài đặt sử dụng hook toàn cục, xét toán đơn giản sau làm ví dụ minh họa : Giả sử ta soạn thảo văn môi trường (Notepad, Microsoft Word, ), viết chương trình theo dõi phím gõ người dùng, phím ‘0’ góc phải bàn phím hình soạn thảo xuất thêm ký tự ‘d’ ‘t’ Phân tích kiện để xác định loại hook phù hợp Theo phát biểu toán trên, ta nghĩ đến hook WH_KEYBOARD, bên cạnh có hook làm nên chuyện, hook WH_GETMESSAGE (nên nhớ Filter Function ứng với loại hook hứng loại thông điệp trả từ GetMessage PeekMessage) Hướng tiếp cận dễ nhận thấy để giải vấn đề chặn thông điệp WM_KEYDOWN WM_KEYUP (không cần chặn hai), kiểm tra phím gì, phím ‘0’ bàn phím số dùng hàm keybd_event để gởi phím ‘d’ ‘t’ Nếu ta dùng hook WH_KEYBOARD, Filter Function gọi xuất message WM_KEYDOWN WM_KEYUP Kết ta không phân biệt rõ hai thông điệp này, Filter Function gọi lần với động tácgõ phím Mặt khác để phân biệt message cần phải thực phép toán bit giá trị lParam, đồng thời phải nhớ khác lParam WM_KEYDOWN với lParam WM_KEYUP Điều tương đối phức tạp Còn ta dùng hook WH_GETMESSAGE, vấn đề đơn giản hơn, việc phân biệt hai message thực tên hai thông điệp Hãy nhớ loại hook này, lParam Filter Function trỏ đến cấu trúc MSG thông điệp hứng Với lý giải vừa nêu, chọn hook WH_GETMESSAGE Tiến hành cài đặt DLL chứa Filter Function hook Đây hook toàn cục, Filter Function phải hàm “export” DLL Đầu tiên, ta định nghĩa thị để “export” hàm : #define EXPORT declspec( dllexport) Từ đây, muốn “export” hàm nào, ta việc dùng lệnh : EXPORT Tên_Hàm(Tham_số_1, Tham_số_2, ) Trong DLL có hàm cần phải “export” : · Hàm cài đặt hook · Hàm gỡ bỏ hook · Filter Function hook Hai hàm đầu ứng dụng cài đặt hook gọi, Filter Function dĩ nhiên gọi HĐH Windows Và sau phiên DLL cho toán : #include "StdAfx.h" // Định nghĩa thị EXPORT #define EXPORT declspec(dllexport) // Export hàm cài đặt, gở bỏ hook EXPORT void WINAPI InstallHook(); EXPORT void WINAPI RemoveHook(); // Export Filter Function EXPORT LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lPram); // Handle DLL HANDLE hDllInst = NULL; // Handle hook cài đặt HHOOK hGetMsgHook = NULL; BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { // Lấy handle DLL hDllInst = hModule; return TRUE; } /* Giả lập nhấn phím (Release=FALSE) hay nhả phím (Release = TRUE) phím có mã phím ảo vk */ void SendKey(BYTE vk, BOOL Release=FALSE) { if (Release) keybd_event(vk, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0); else keybd_event(vk, 0, KEYEVENTF_EXTENDEDKEY, 0); } // Cài đặt hook EXPORT void WINAPI InstallHook() { if (hGetMsgHook == NULL) hGetMsgHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)GetMsgProc, (HINSTANCE)hDllInst, 0); } // Gỡ bỏ hook EXPORT void WINAPI RemoveHook() { if (hGetMsgHook != NULL) { UnhookWindowsHookEx(hGetMsgHook); hGetMsgHook = NULL; } } // Filter Function cho hook EXPORT LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam) { MSG* p = (MSG*)lParam; // Chỉ xử lý message lấy khỏi hàng đợi if ( (nCode >= 0) && (wParam == PM_REMOVE) ) { // Thông điệp WM_KEYDOWN if (p->message == WM_KEYDOWN) // Phim nhấn phím ‘0’ góc phải bàn phím if (p->wParam == VK_NUMPAD0) { SendKey(0x44); // Gởi phím ‘d’ SendKey(0x54); // Gởi phím ‘t’ } } // Nếu nCode // return (CallNextHookEx(hGetMsgHook, nCode, wParam, lParam)); } Sử dụng DLL hoàn chỉnh chương trình Đầu tiên định nghĩa thị IMPORT để “import” hàm DLL dùng cho ứng dụng #define IMPORT declspec( dllimport ) Sau dùng thị để “import” hai hàm : InstallHook RemoveHook Việc sử dụng hook đơn giản, ta cần vào hàm xử lý message cho cửa sổ ứng dụng, chặn message WM_CREATE WM_DESTROY đoạn code sau minh họa : case WM_CREATE : InstallHook(); // Các xử lý khác break; case WM_DESTROY : RemoveHook(); // Các xử lý khác break; Sau cài đặt hook, việc gọi Filter Function trách nhiệm Windows, nhiệm vụ ta từ lúc chờ người dùng kết thúc ứng dụng gỡ bỏ hook Đến xem ta giải toán đặt Qua ví dụ này, thiết nghĩ việc cài đặt hook xem khó Mấu chốt vấn đề phải chọn loại hook phù hợp nắm thông tin liên quan đến kiện ta muốn chặn cách đầy đủ, xác [...]... 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, // handle to current hook int nCode, // hook code passed to hook procedure WPARAM wParam, // value passed to hook procedure LPARAM lParam // value passed to hook. .. 0, KEYEVENTF_EXTENDEDKEY, 0); } // Cài đặt hook EXPORT void WINAPI InstallHook() { if (hGetMsgHook == NULL) hGetMsgHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)GetMsgProc, (HINSTANCE)hDllInst, 0); } // Gỡ bỏ hook EXPORT void WINAPI RemoveHook() { if (hGetMsgHook != NULL) { UnhookWindowsHookEx(hGetMsgHook); hGetMsgHook = NULL; } } // Filter Function cho hook EXPORT LRESULT CALLBACK GetMsgProc(int... return (CallNextHookEx(hGetMsgHook, nCode, wParam, lParam)); } Sử dụng DLL và hoàn chỉnh chương trình Đầu tiên là định nghĩa chỉ thị IMPORT để “import” một hàm trong DLL dùng cho ứng dụng #define IMPORT declspec( dllimport ) Sau đó dùng chỉ thị này để “import” hai hàm : InstallHook và RemoveHook Việc sử dụng hook bây giờ sẽ cực kỳ đơn giản, ta chỉ cần vào hàm xử lý message cho cửa sổ của ứng dụng, chặn... 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. .. chương trình theo dõi các phím được gõ của người dùng, nếu là phím ‘0’ ở góc phải bàn phím thì trên màn hình soạn thảo sẽ xuất hiện thêm 2 ký tự ‘d’ và ‘t’ Phân tích sự kiện để xác định loại hook phù hợp Theo phát biểu của bài toán trên, ta nghĩ ngay đến hook WH_KEYBOARD, bên cạnh đó cũng có một hook có thể làm nên chuyện, đấy chính là hook WH_GETMESSAGE (nên nhớ rằng Filter Function ứng với loại hook. .. cài đặt hook · Hàm gỡ bỏ hook · Filter Function của hook Hai hàm đầu được ứng dụng cài đặt hook gọi, còn Filter Function dĩ nhiên sẽ được gọi bởi HĐH Windows Và sau đây là một phiên bản DLL khả dĩ cho bài toán trên : #include "StdAfx.h" // Định nghĩa chỉ thị EXPORT #define EXPORT declspec(dllexport) // Export 2 hàm cài đặt, gở bỏ hook EXPORT void WINAPI InstallHook(); EXPORT void WINAPI RemoveHook();... trả thông điệp về cho ứng dụng, thông điệp sẽ được chuyển cho Filter Function của hook để hàm này có thể thực hiện một số thao tác kiểm tra, chỉnh sửa thông tin của message Tuy nhiên, Filter Function không thể hủy bỏ thông điệp mà nó nhận được Đây là nguyên tắc cơ bản khi sử dụng hook WH_GETMESSAGE Filter Function của hook này có dạng sau : LRESULT CALLBACK GetMsgProc( int code, // hook code WPARAM wParam,... Message vẫn còn nằm trong hàng đợi, điều này đồng nghĩa với việc ứng dụng gọi PeekMessege với tuỳ chọn PM_NOREMOVE Message đã được lấy ra khỏi hàng đợi, ứng dụng đã gọi GetMessage, hoặc PeekMessage với tuỳ chọn PM_REMOVE lParam : trỏ đến cấu trúc MSG chứa thông tin chi tiết về message IV.Cài đặt và sử dụng một hook toàn cục Phần này sẽ nêu vắn tắt cách cài đặt và sử dụng một hook toàn cục, chúng ta sẽ xét... hook procedure ); Tham số đầu tiên 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 Ba tham số tiếp theo là những giá trị mà Windows truyền cho Filter Function.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 ta đang cài đặt cho phép huỷ bỏ sự kiện,... hàm CallNextHookEx Có một thực tế mà các lập trình viên buộc phải chấp nhận : họ sẽ không thể biết được vị trí Filter Function của mình trong chuỗi các Filter Function Bởi vì khi ta gọi hàm CallNextHookEx, Windows mới là đối tượng quyết định xem phải chọn hàm nào để bàn giao sự kiện, và quá trình này dĩ nhiên đã được HĐH giấu kín Do đó, một cách khôn ngoan (và bắt buộc) để đảm bảo an toàn hệ thống là

Ngày đăng: 28/10/2015, 18:04

Từ khóa liên quan

Tài liệu cùng người dùng

Tài liệu liên quan