Từ 1 tới 9 trên tổng số 9 kết quả

Đề tài: Tại sao code của mình không hook cục bộ đến cửa sổ NotePad được?

  1. #1
    Ngày gia nhập
    07 2011
    Nơi ở
    Moscow-Russia
    Bài viết
    154

    Mặc định Tại sao code của mình không hook cục bộ đến cửa sổ NotePad được?

    Chào mọi người,
    Mình thử hook cục bộ đối với cửa sổ Edit của NotePad.
    Mục đích: khi nhấn một phím bất kỳ trên cửa sổ này thì phát ra một tiếng beep.
    Cách làm: Mình dùng hàm SetWindowsHookEx để cài hook. Hàm lọc mình để cùng code file với hàm main, và do đó tham số thứ 3 của hàm SetWindowsHookEx mình sẽ đặt là 0; còn tham số cuối cùng mình đặt là threadId của NotePad (được trả về từ hàm GetWindowThreadProcessId, và nó khác 0 - mình đã kiểm tra). Nhưng kết quả không nhận được bất cứ điều gì.
    Code của mình bên dưới:
    Visual C++ Code:
    1. #include <windows.h>
    2.  
    3. HHOOK keyboardHook;
    4.  
    5. LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
    6. {
    7.     if (wParam == WM_KEYDOWN && nCode == HC_ACTION)
    8.     {
    9.         Beep(440, 440);
    10.         return 0;
    11.     }
    12.     return CallNextHookEx(keyboardHook, nCode, wParam, lParam);
    13. }
    14.  
    15. int main()
    16. {
    17.     HWND hParent = FindWindow(L"Notepad", L"Untitled - Notepad");
    18.     HWND hChild = FindWindowEx(hParent, NULL, L"Edit", L"");
    19.     DWORD processId;
    20.     DWORD threadId = GetWindowThreadProcessId(hChild, &processId);
    21.  
    22.     keyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardProc, 0, threadId); // Tại sao không làm việc???
    23.  
    24.     MSG msg{ 0 };
    25.     while (GetMessage(&msg, NULL, 0, 0) != 0);
    26.  
    27.     UnhookWindowsHookEx(keyboardHook);
    28.  
    29.     return 0;
    30. }
    Khi mình thay tham số cuối cùng bằng 0 (hook toàn hệ thống) thì nó làm việc (nhấn ở bất cứ nơi đâu cũng đều nhận về tiếng Beep - không chỉ riêng NotePad, nhưng mình chỉ muốn hook mỗi thằng NotePad thôi).

    Mong các bạn góp ý để mình làm đúng mục đích của mình. Xin cảm ơn mọi người rất nhiều.
    A good beginning and a good ending !

  2. #2
    Ngày gia nhập
    02 2014
    Nơi ở
    TP.HCM
    Bài viết
    1,006

    1. Bạn phải thiết lập Hook toàn cục trên dll (có nghĩa chương trình bạn phải có cả exe lẫn dll).
    2. Không nên dùng GetMessage khi chương trình bạn không tạo ra cửa sổ nào để thư viện thông báo ngược trở lại khi có sự kiện phím nhấn. Vòng lặp của bạn là không tác dụng và chỉ làm dll thường trú trên HĐH cho tới hết phiên làm việc của Windows. Nó dẫn tới bạn không thể biên dịch lại cả exe và dll trừ khi vào Task Manager tắt thể hiện đang chạy. Tốt nhất nên tạo cửa sổ trên chương trình chính để điều khiển và kiểm tra hook.
    3. Nếu rảnh mình sẽ làm một test nho nhỏ minh họa sau.
    .
    .

  3. #3
    Ngày gia nhập
    07 2011
    Nơi ở
    Moscow-Russia
    Bài viết
    154

    Cảm ơn Minh Hoàng đã trả lời bài viết của mình. Mình đang cần hook cục bộ chứ không phải hook toàn cục (vì hook toàn cục như mình nói là mình đã làm đc, ko cần dll, chỉ cần đặt tham số cuối cùng là 0). Mình chỉ cần hook NotePad, không hook những ứng dụng khác. Mong bạn có thời gian cho mình một giải pháp. Chân thành cảm ơn bạn.

  4. #4
    Ngày gia nhập
    02 2014
    Nơi ở
    TP.HCM
    Bài viết
    1,006

    Định nghĩa hook toàn cục và cục bộ nên hiểu là :
    . Cục bộ : hook với các đối tượng do chính tiến trình của chương trình tạo ra
    . Toàn cục : hook các đối tượng của các tiến trình khác tạo ra.

    Riêng với mục đích của chương trình bạn, thì rõ ràng là hook cửa sổ soạn thảo của tiếp trình Notepad nên phải sử dụng hook toàn cục.

    Một ví dụ minh họa :

    Tập tin .def trong dự án Dll
    Visual C++ Code:
    1. LIBRARY HookNotepadDll.dll
    2. EXPORTS
    3.     SaveCallWnd     @1
    4.     KeyboardProc    @2

    Tập tin .cpp trong dự án Dll
    Visual C++ Code:
    1. #ifdef __cplusplus
    2. #define EXPORT extern "C" __declspec (dllexport)
    3. #else
    4. #define EXPORT __declspec (dllexport)
    5. #endif
    6.  
    7. #include <Windows.h>
    8.  
    9. #define WM_NOTEPADKEYDOWN   (WM_USER + 1)       // Thông điệp từ dll gởi tới chương trình chính thông báo Notepad nhấn phím
    10. HWND g_hExeWnd = NULL;                          // Thẻ cửa sổ chương trình chính
    11.  
    12. int WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, PVOID pVoid)
    13. {
    14.     return TRUE;
    15. }
    16.  
    17. EXPORT void CALLBACK SaveCallWnd(HWND hWnd) { g_hExeWnd = hWnd; }
    18.  
    19. EXPORT LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
    20. {
    21.     if (nCode < 0)      // Không được xử lý thông điệp
    22.         return CallNextHookEx(NULL, nCode, wParam, lParam);
    23.     // Xử lý khi nhấn phím trên cửa sổ soạn thảo của Notepad
    24.     if (nCode == HC_ACTION && (lParam & 0x80000000))
    25.     {
    26.         // Nên dùng Post/Send tùy theo mức độ cần xử lý: ngắn gọn dùng Send, dài dòng dùng Post
    27.         // Nếu dùng Send thì Notepad sẽ tạm thời đông cứng trong khi Main xử lý
    28.         SendMessage(g_hExeWnd, WM_NOTEPADKEYDOWN, wParam, lParam);
    29.         //PostMessage(g_hExeWnd, WM_NOTEPADKEYDOWN, wParam, lParam);
    30.     }
    31.     return CallNextHookEx(NULL, nCode, wParam, lParam);
    32. }

    Tập tin .cpp trong dự án tạo chương trình chính
    Visual C++ Code:
    1. #define UNICODE
    2. #include <windows.h>
    3.  
    4. typedef void(WINAPI * PSAVECALLWND) (HWND);     // Kiểu hàm trong Dll
    5. #define WM_NOTEPADKEYDOWN   (WM_USER + 1)       // Thông điệp thống nhất số hiệu với bên Dll
    6.  
    7. LPCTSTR     g_AppName = L"HookNotepad";
    8.  
    9. class CLibrary
    10. {
    11. private:
    12.     HMODULE     m_hModule;
    13.     HOOKPROC    m_HookProc;
    14.     HHOOK       m_hHook;
    15.  
    16. public:
    17.     // Khởi dựng - hủy
    18.     CLibrary() : m_hModule(NULL), m_HookProc(NULL), m_hHook(NULL) {}
    19.     ~CLibrary()
    20.     {
    21.         if (m_hHook)
    22.             UnhookWindowsHookEx(m_hHook);
    23.         if (m_hModule)
    24.             FreeLibrary(m_hModule);
    25.     }
    26.     bool Initialize(HWND hwnd)
    27.     {
    28.         // Kiểm tra cửa sổ Notepad
    29.         HWND hParent = FindWindow(L"Notepad", L"Untitled - Notepad");
    30.         if (!hParent)
    31.         {
    32.             MessageBox(hwnd, L"Không tìm thấy cửa sổ Notepad, hoặc tiêu đề đã thay đổi !!!", g_AppName, MB_OK | MB_ICONERROR);
    33.             return false;
    34.         }
    35.         HWND hChild = FindWindowEx(hParent, NULL, L"Edit", L"");
    36.         if (!hChild)
    37.         {
    38.             MessageBox(hwnd, L"Notepad đã thay đổi tên lớp soạn thảo, hoặc nội dung đã thay đổi !!!", g_AppName, MB_OK | MB_ICONERROR);
    39.             return false;
    40.         }
    41.         //
    42.         DWORD processId;
    43.         DWORD threadId = GetWindowThreadProcessId(hChild, &processId);
    44.         // Kiểm tra thư viện
    45.         m_hModule = LoadLibrary(L"HookNotepadDll.dll");
    46.         if (!m_hModule)
    47.         {
    48.             MessageBox(hwnd, L"Không tìm thấy thư viện HookNotepadDll.dll !!!", g_AppName, MB_OK | MB_ICONERROR);
    49.             return false;
    50.         }
    51.         m_HookProc = (HOOKPROC)GetProcAddress(m_hModule, "KeyboardProc");
    52.         if (!m_HookProc)
    53.         {
    54.             MessageBox(hwnd, L"Thư viện HookNotepadDll.dll đã sai hỏng !!!", g_AppName, MB_OK | MB_ICONERROR);
    55.             return false;
    56.         }
    57.         // Phần mã cộng thêm nếu muốn xử lý hook dài
    58.         PSAVECALLWND pSave = (PSAVECALLWND)GetProcAddress(m_hModule, "SaveCallWnd");
    59.         if (!pSave)
    60.         {
    61.             MessageBox(hwnd, L"Thư viện HookNotepadDll.dll đã sai hỏng !!!", g_AppName, MB_OK | MB_ICONERROR);
    62.             return false;
    63.         }
    64.         pSave(hwnd);        // Thư viện sẽ lưu thẻ cửa sổ chương trình từ hàm này
    65.         // Bắt đầu Hook
    66.         m_hHook = SetWindowsHookEx(WH_KEYBOARD, m_HookProc, m_hModule, threadId);
    67.         return true;
    68.     }
    69. };
    70.  
    71. class CMainWnd
    72. {
    73. private:
    74.     HINSTANCE       m_hInst = NULL;
    75.     HWND            m_hWnd = NULL;
    76.     HWND            m_hbtBegin = NULL;
    77.     HWND            m_hbtEnd = NULL;
    78.     CLibrary    *   m_pLibrary = NULL;
    79.     // Thủ tục Window
    80.     static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
    81.     {
    82.         if (message == WM_CREATE)
    83.         {
    84.             LPCREATESTRUCT pcs = reinterpret_cast<LPCREATESTRUCT>(lparam);
    85.             CMainWnd * p = reinterpret_cast<CMainWnd*>(pcs->lpCreateParams);
    86.             SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(p));
    87.             return p->OnCreate(pcs->hInstance, hwnd);
    88.         }
    89.         CMainWnd * p = reinterpret_cast<CMainWnd*>(static_cast<LONG_PTR>(GetWindowLongPtr(hwnd, GWLP_USERDATA)));
    90.         if (p)
    91.         {
    92.             switch (message)
    93.             {
    94.             case WM_SIZE:           return p->OnSize(lparam);
    95.             case WM_COMMAND:        return p->OnCommand(wparam, lparam);
    96.             case WM_DESTROY:        return p->OnDestroy();
    97.  
    98.             case WM_NOTEPADKEYDOWN: return p->OnNotepadKeydown(wparam, lparam);     // Thông điệp từ Dll
    99.             }
    100.         }
    101.         return DefWindowProc(hwnd, message, wparam, lparam);
    102.     }
    103.     // Các bộ xử lý thông điệp
    104.     LRESULT OnCreate(HINSTANCE hInst, HWND hwnd)
    105.     {
    106.         m_hInst = hInst;
    107.         m_hWnd = hwnd;
    108.         // Tạo các button
    109.         m_hbtBegin = CreateWindow(L"button", L"Begin", WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, hwnd,
    110.             reinterpret_cast<HMENU>(static_cast<UINT_PTR>(1001)), hInst, NULL);
    111.         m_hbtEnd = CreateWindow(L"button", L"End", WS_CHILD | WS_VISIBLE | WS_DISABLED, 0, 0, 0, 0, hwnd,
    112.             reinterpret_cast<HMENU>(static_cast<UINT_PTR>(1002)), hInst, NULL);
    113.         return 0;
    114.     }
    115.     LRESULT OnSize(LPARAM lparam)
    116.     {
    117.         int xCenter = LOWORD(lparam) / 2;
    118.         int yCenter = HIWORD(lparam) / 2;
    119.         // Di chuyển các Button
    120.         MoveWindow(m_hbtBegin, xCenter - 90, yCenter - 11, 80, 22, TRUE);
    121.         MoveWindow(m_hbtEnd, xCenter + 10, yCenter - 11, 80, 22, TRUE);
    122.         return 0;
    123.     }
    124.     LRESULT OnCommand(WPARAM wparam, LPARAM lparam)
    125.     {
    126.         switch (LOWORD(wparam))
    127.         {
    128.         case 1001:  // Button Begin
    129.             m_pLibrary = new CLibrary();
    130.             if (!m_pLibrary->Initialize(m_hWnd))
    131.             {
    132.                 delete m_pLibrary;
    133.                 m_pLibrary = NULL;
    134.                 return 0;
    135.             }
    136.             // On/Off cho phép các button
    137.             EnableWindow(m_hbtBegin, FALSE);
    138.             EnableWindow(m_hbtEnd, TRUE);
    139.             return 0;
    140.         case 1002:  // Button End
    141.             if (m_pLibrary)
    142.             {
    143.                 delete m_pLibrary;
    144.                 m_pLibrary = NULL;
    145.             }
    146.             // On/Off cho phép các button
    147.             EnableWindow(m_hbtBegin, TRUE);
    148.             EnableWindow(m_hbtEnd, FALSE);
    149.             return 0;
    150.         }
    151.         return DefWindowProc(m_hWnd, WM_COMMAND, wparam, lparam);
    152.     }
    153.     LRESULT OnDestroy()
    154.     {
    155.         if (m_pLibrary)
    156.             delete m_pLibrary;
    157.         PostQuitMessage(0);
    158.         return 0;
    159.     }
    160.  
    161.     LRESULT OnNotepadKeydown(WPARAM wparam, LPARAM lparam)
    162.     {
    163.         MessageBox(m_hWnd, L"Notepad - Keydown", g_AppName, MB_OK | MB_ICONINFORMATION);
    164.         return 0;
    165.     }
    166.  
    167. public:
    168.     int Create(HINSTANCE hInst, int nShow)
    169.     {
    170.         // Đăng ký lớp
    171.         WNDCLASS    w;
    172.         w.cbClsExtra = 0;
    173.         w.cbWndExtra = 0;
    174.         w.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH);
    175.         w.hCursor = LoadCursor(NULL, IDC_ARROW);
    176.         w.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    177.         w.hInstance = hInst;
    178.         w.lpfnWndProc = WndProc;
    179.         w.lpszClassName = g_AppName;
    180.         w.lpszMenuName = NULL;
    181.         w.style = CS_HREDRAW | CS_VREDRAW;
    182.         if (!RegisterClass(&w))
    183.             return 0;
    184.         // Tạo cửa sổ
    185.         HWND hwnd = CreateWindow(g_AppName, g_AppName, WS_OVERLAPPEDWINDOW, 400, 400, 260, 80, NULL, NULL, hInst, this);
    186.         if (!hwnd)
    187.             return 0;
    188.         ShowWindow(hwnd, nShow);
    189.         UpdateWindow(hwnd);
    190.         // Vòng lặp thông điệp
    191.         MSG     msg;
    192.         while (GetMessage(&msg, NULL, 0, 0))
    193.         {
    194.             TranslateMessage(&msg);
    195.             DispatchMessage(&msg);
    196.         }
    197.         return (int)msg.wParam;
    198.     }
    199. };
    200. int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmd, int nShow)
    201. {
    202.     CMainWnd    wnd;
    203.     return wnd.Create(hInst, nShow);
    204. }



    Tạo ra tiếng Beep mình không thử nghiệm.
    .
    .
    .
    Attached Thumbnails Attached Thumbnails Hook.png  
    Đã được chỉnh sửa lần cuối bởi MHoang : 29-08-2021 lúc 05:08 PM.

  5. #5
    Ngày gia nhập
    07 2011
    Nơi ở
    Moscow-Russia
    Bài viết
    154

    Cảm ơn bạn rất nhiều đã cho ví dụ và khái niệm lại cho mình về local hook và global hook.
    Mình sẽ nghiên cứu thêm. Vì mình đang làm trên Console nên thật khó để viết lại mã của bạn vào đó. Mình sẽ cố gắng thử. Một lần nữa cảm ơn bạn rất nhiều.
    A good beginning and a good ending !

  6. #6
    Ngày gia nhập
    02 2014
    Nơi ở
    TP.HCM
    Bài viết
    1,006

    Mặc định Tại sao code của mình không hook cục bộ đến cửa sổ NotePad được?

    Không phải khái niệm lại đâu bạn, mình chỉ đi sâu hơn trong các trường hợp cụ thể mà thôi. Thực ra định nghĩa toàn cục và cục bộ theo Windows vẫn đúng nhưng nó hơi mù mờ dễ tạo ra nhầm lẫn.
    Chúng ta nên hiểu khi Windows nói toàn cục là tất cả các tiến trình nhưng thực ra là hook các đối tượng của tiến trình hệ thống (các đối tượng hook ở đây là các bàn phím, chuột,...). Hook toàn cục cần thông qua 1 Dll nhưng với tiến trình hệ thống thì đã có sẵn các Dll trong máy rồi nên không cần thể hiện trong hàm SetWindowsHookEx. Với các đối tượng của các tiến trình khác (như của bạn) thì chúng ta phải cung cấp Module Dll và thủ tục Hook trong Dll một cách tường minh cho hàm trên.
    Đó là suy nghĩ của mình khi phát biểu "Hook toàn cục là hook đối tượng của tiến trình khác", như vậy nó ít mù mờ hơn định nghĩa gốc của Windows.
    .
    .

  7. #7
    Ngày gia nhập
    07 2011
    Nơi ở
    Moscow-Russia
    Bài viết
    154

    Cảm ơn bạn.
    Mình đọc nhiều tài liệu nước ngoài thấy họ nói là local hook là hook một tiến trình cụ thể và lúc này tham số cuối cùng của hàm SetWindowHookEx được đặt là handle của thread cần hook. Còn global hook là hook tất cả các tiến trình của toàn hệ thống (tiến trình nào cũng bị hook), lúc đó tham số tuơng ứng luôn là 0.
    Tuy nhiên thì cũng không quá quan trọng việc gọi đó, mà quá trình thực hành mình cần biết cách đặt tham số và thực hiện các quy trình cho đúng với mục đích của mình.
    Một lần nữa rất cảm ơn bạn. Mình sẽ quay lại chủ để khi có thêm các câu hỏi phát sinh. Chúc bạn luôn thành công và hỗ trợ các bạn mới học (như mình) nhiều hơn nữa.
    A good beginning and a good ending !

  8. #8
    Ngày gia nhập
    02 2014
    Nơi ở
    TP.HCM
    Bài viết
    1,006

    Mặc định Hook Notepad : Gõ chữ thường thành chữ in và ngược lại sử dụng WH_GETMESSAGE.

    Thêm một chương trình ngắn gọn (Console) để Hook Notepad.

    Mục đích : Thay đổi ký tự thường thành ký tự in và ngược lại (chỉ cho các ký tự Ascii) khi người dùng gõ nhập ký tự vào cửa sổ soạn thảo của Notepad.

    Tập tin DllHook.cpp
    Visual C++ Code:
    1. #ifdef __cplusplus
    2. #define EXPORT extern "C" __declspec (dllexport)
    3. #else
    4. #define EXPORT __declspec (dllexport)
    5. #endif
    6.  
    7. #include <Windows.h>
    8.  
    9. BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, PVOID pVoid)
    10. {
    11.     return TRUE;
    12. }
    13. EXPORT LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)
    14. {
    15.     if (nCode == HC_ACTION)             // Được phép xử lý
    16.     {
    17.         LPMSG   pMsg = (LPMSG)lParam;
    18.         switch (pMsg->message)
    19.         {
    20.         case WM_CHAR:
    21.             if (isalpha((int)pMsg->wParam))                                 // Nếu là ký tự AnphaBet
    22.                 pMsg->wParam += (pMsg->wParam < 'a') ? (0x20) : (-0x20);    // Chuyển bật chữ in/thường
    23.             break;
    24.         }
    25.     }
    26.     return CallNextHookEx(NULL, nCode, wParam, lParam);
    27. }

    Tập tin ExeHook.cpp
    Visual C++ Code:
    1. #include <windows.h>
    2. #include <stdio.h>
    3.  
    4. int main()
    5. {
    6.     HMODULE     hModule;                // Module thư viện
    7.     HOOKPROC    pHookProc;              // Thủ tục Hook trong Module
    8.     HHOOK       hHook;                  // Thẻ Hook
    9.     HWND        hParent, hChild;        // Thẻ cửa sổ Notepad và cửa sổ soạn thảo bên trong
    10.     DWORD       processId, threadId;    // ID tiến trình Notepad và ID tiểu trình soạn thảo bên trong
    11.  
    12.     if (!(hParent = FindWindow(TEXT("Notepad"), NULL)))
    13.     {
    14.         printf("Error: Notepad window was not found !!!");
    15.         getchar();
    16.         return 0;
    17.     }
    18.     if (!(hChild = FindWindowEx(hParent, NULL, TEXT("Edit"), NULL)))
    19.     {
    20.         printf("Error: Edit window was not found !!!");
    21.         getchar();
    22.         return 0;
    23.     }
    24.     if (!(hModule = LoadLibrary(TEXT("DllHook.dll"))))
    25.     {
    26.         printf("Error: DllHook.dll was not found !!!");
    27.         getchar();
    28.         return 0;
    29.     }
    30.     if (!(pHookProc = (HOOKPROC)GetProcAddress(hModule, "GetMsgProc")))
    31.     {
    32.         FreeLibrary(hModule);
    33.         printf("Error: GetMsgProc() was not found !!!");
    34.         getchar();
    35.         return 0;
    36.     }
    37.     threadId = GetWindowThreadProcessId(hChild, &processId);
    38.     hHook = SetWindowsHookEx(WH_GETMESSAGE, pHookProc, hModule, threadId);      // Bắt đầu Hook
    39.     printf("Ready !!!");
    40.     getchar();
    41.     UnhookWindowsHookEx(hHook);                                                 // Kết thúc Hook
    42.     FreeLibrary(hModule);                                                       // Giải phóng thư viện
    43.     return 0;
    44. }

    Vì Hook WH_GETMESSAGE nên Solution sẽ được xây dựng theo x64 và dự án DllHook không cần thêm tập tin .def để định nghĩa hàm xuất.
    Nguyên do là chương trình Notepad hiện nay đều là chạy cho nền đích 64bits trên Windows.

    Attached Files Attached Files

  9. #9
    Ngày gia nhập
    07 2011
    Nơi ở
    Moscow-Russia
    Bài viết
    154

    Cảm ơn bạn Minh Hoàng nhiều nhé. Mình đã hiểu hơn được rất nhiều.
    A good beginning and a good ending !

Quyền hạn của bạn

  • Bạn không thể gửi đề tài mới
  • Bạn không thể gửi bài trả lời
  • Bạn không thể gửi các đính kèm
  • Bạn không thể chỉnh sửa bài viết của bạn