Post

UsbHook

UsbHook

UsbHook 看到这个题目,你一定会想 Usb钩子是个什么东西,能干什么,还叫这么怪的名字,那给它起个更好听的名字吧UsbSpy Usb间谍。

UsbSpy 产生的背景

在上学的时候,教人工智能的老师有个习惯,就是从来不给别人烤自己上课用的幻灯片。上课的时候,插自己的U盘到教室的机子,然后上放幻灯片,从来不把幻灯片烤到教室的机子上。别的老师不光给学生烤自己的幻灯片,考试前还划重点。这个老师既不烤幻灯片,还不划重点。快到考试了,同学都有些急了,就策划说做一个什么工具当U盘一插就拷U盘上的全部东西到硬盘的预先指定位置。就因为这个原因UsbSpy诞生了,当U盘插入时截获系统消息:WM_DEVICECHANGE 得到U盘盘符。拷贝U盘所有目录下的 .ppt 文件到 D:\ppt 下。话不多讲,开始UsbSpy的制作吧。

要写在前面的话

由于各种原因本文没有给出,UsbSpy 全部源代码,本文附加了 .Net下 全局 Hook 的实现。留下了没有在 .Net下动态加载/卸载一个的 AppDomain 中动态绑定事件的遗憾。UsbSpy的结局: 最后虽然做出了UspSpy但是没人感给老师用的机子安装,最后还是熬夜复习赶考试了,最后还是通过了。

全局Hook只能定义在Dll中下面是Dll的定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
//定义回调函数 
LRESULT CALLBACK CallBackProc(int nCode,WPARAM wParam,LPARAM lParam)  
{   
    MSG *pMsg = (MSG *)lParam; 
    //HWND hWnd = ::FindWindow("#32770" , NULL); //"MfcHookApp" 
    if ((pMsg->message == WM_DEVICECHANGE) && (!bInsert))  
    {  
        bInsert=true; 
        MessageBox(NULL, "UsbOK!", "Hook Message", MB_OK); 
        ::PostMessage(hWndMain, WM_INST, wParam, lParam); 
    }  
    return (CallNextHookEx(hHook, nCode, wParam, lParam));  
}  

//安装钩子  
BOOL HOOKAPIFUNC InstallHook(HWND hWndm)  
{  
    //只针对 我的电脑这个进程  
    HWND hWnd = ::FindWindow("CabinetWClass", NULL); 
    //Get The handle.  
    DWORD dwThreadId = 0; 
    //Set the Thread number.  
    if (hWnd != NULL)  
    {  
        dwThreadId = ::GetWindowThreadProcessId(hWnd, &dwThreadId); 
    }  
    if (dwThreadId != 0)  
    {  
        hWndMain=hWndm; 
        hHook = SetWindowsHookEx(WH_GETMESSAGE, CallBackProc, hInstance, dwThreadId); 
        if (hHook == NULL||hWndMain == NULL)  
        {  
            MessageBox(NULL,"Hook Failed!", "Hook Message",MB_OK); 
            return false;  
        }  
        MessageBox(NULL,"Hook Succeed!", "Hook Message",MB_OK); 
        return true;  
    }

    //针对 所有进程 全局的  
    hWndMain=hWndm; 
    hHook = SetWindowsHookEx(WH_GETMESSAGE, CallBackProc, hInstance, 0); 
    if (hHook == NULL||hWndMain == NULL)  
    {  
        MessageBox(NULL,"Hook Failed!", "Hook Message",MB_OK); 
        return false;  
    }  
    
    MessageBox(NULL,"Hook Succeed!", "Hook Message",MB_OK); 
    return true;  
} 

//卸载钩子  
BOOL HOOKAPIFUNC UninstallHook()  
{
    return (BOOL)UnhookWindowsHookEx(hHook); 
}   

CMfcHookDllApp::CMfcHookDllApp()  
{  
    // TODO: add construction code here,  
    // Place all significant initialization in InitInstance  
}  

// The one and only CMfcHookDllApp object  

#pragma data_seg(".SHARED")  

static HHOOK hHook = NULL; //定义全局钩子 

#pragma data_seg()  

#define HOOKAPIFUNC extern "C" __declspec(dllexport)  

#define WM_INST (WM_USER+200) //定义用户自定义消息  

//HoolApp部分  

//安装钩子  
void CMfcHookAppDlg::InstallHook(void)  
{  
    HINSTANCE hInstDLL = NULL;  

    typedef BOOL (*insHookFunc)(HWND hWnd); //();表示不带参数这里表示带参数   

    insHookFunc insHook = NULL; 

    if ((hInstDLL = LoadLibrary((LPCTSTR)"MfcHookDll.dll")) != NULL)  
    {  
        //insHook = (insHookFunc)GetProcAddress(hInstDLL, "InstallHook");  
        insHook = (insHookFunc)GetProcAddress(hInstDLL,MAKEINTRESOURCE(1));//使用函数名和用MAKEINTRESOURCE用名字编码也可以做到 
        
        if (insHook != NULL)  
        {
            insHook(m_hWnd); 
        }  
    }  
}

//卸载钩子  
void CMfcHookAppDlg::UninstallHook(void)  
{  
    HINSTANCE hInstDLL = NULL;  
    typedef BOOL (*uninsHookFunc)();  
    uninsHookFunc uninsHook = NULL; 

    if ((hInstDLL = LoadLibrary((LPCTSTR)"MfcHookDll.dll")) != NULL)  
    {  
        uninsHook = (uninsHookFunc)GetProcAddress(hInstDLL,MAKEINTRESOURCE(2)); 
        //uninsHook = (uninsHookFunc)GetProcAddress(hInstDLL, "UninstallHook");

        if (uninsHook != NULL)  
        {  
            uninsHook(); 
        }  
        FreeLibrary(hInstDLL); 
    }  
}  

//定义用户回调函数  
LRESULT CMfcHookAppDlg::OnInst(WPARAM wParam, LPARAM lParam)  
{   
    // TODO: 处理用户自定义消息   
    MessageBox("OK","Hook"); 
    return 0;  
}   

BEGIN_MESSAGE_MAP(CMfcHookAppDlg, CDialog)  
ON_WM_PAINT()  
ON_WM_QUERYDRAGICON()  
//}}AFX_MSG_MAP  
ON_BN_CLICKED(IDC_BUTTON_CLOSE, OnBnClickedButtonClose)  
ON_BN_CLICKED(IDC_BUTTON_INSTALL, OnBnClickedButtonInstall)  
ON_BN_CLICKED(IDC_BUTTON_UNINSTALL, OnBnClickedButtonUninstall)  
ON_MESSAGE(WM_INST, OnInst) //注意这个消息映射 是自己添加的不是系统生成的  
ON_WM_CLOSE()  
END_MESSAGE_MAP()

.Net下的全局钩子的定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
//完全参考 https://www.codeproject.com/csharp/globalhook.asp 
//自己包装了Dll,Exe用工程引入了Dll
//Exe部分
void MainFormLoad(object sender, System.EventArgs e)  
{  
    actHook= new DotNetHookDll(); // crate an instance 
    // hang on events  
    actHook.OnMouseActivity+=new MouseEventHandler(MouseMoved); 
    actHook.KeyDown+=new KeyEventHandler(MyKeyDown); 
    actHook.KeyPress+=new KeyPressEventHandler(MyKeyPress); 
    actHook.KeyUp+=new KeyEventHandler(MyKeyUp); 
}  

public void MouseMoved(object sender, MouseEventArgs e)  
{  
    labelMousePosition.Text=String.Format("x={0} y={1}", e.X, e.Y); 
    if (e.Clicks>0) LogWrite("MouseButton - " + e.Button.ToString());  
}  

public void MyKeyDown(object sender, KeyEventArgs e)  
{  
    LogWrite("KeyDown - " + e.KeyData.ToString());  
}  

public void MyKeyPress(object sender, KeyPressEventArgs e)  
{  
    LogWrite("KeyPress - " + e.KeyChar); 
}  

public void MyKeyUp(object sender, KeyEventArgs e)  
{  
    LogWrite("KeyUp - " + e.KeyData.ToString());  
}  

private void LogWrite(string txt)  
{  
    textBox.AppendText(txt + Environment.NewLine); 
    textBox.SelectionStart = textBox.Text.Length; 
}  

//Dll部分  
public event MouseEventHandler OnMouseActivity; //定义事件  
public event KeyEventHandler KeyDown;  
public event KeyPressEventHandler KeyPress;  
public event KeyEventHandler KeyUp;  

public delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);//定义代理 
static int hMouseHook = 0; //Declare mouse hook handle as int. 
static int hKeyboardHook = 0; //Declare keyboard hook handle as int. 

//values from Winuser.h in Microsoft SDK.  
public const int WH_MOUSE_LL = 14; //mouse hook constant 
public const int WH_KEYBOARD_LL = 13; //keyboard hook constant  

HookProc MouseHookProcedure; //Declare MouseHookProcedure as HookProc type.  
HookProc KeyboardHookProcedure; //Declare KeyboardHookProcedure as HookProc type.  

//Declare wrapper managed POINT class.  
[StructLayout(LayoutKind.Sequential)]  
public class POINT   
{  
    public int x;  
    public int y;  
}  

//Declare wrapper managed MouseHookStruct class.  
[StructLayout(LayoutKind.Sequential)]  
public class MouseHookStruct   
{  
    public POINT pt;  
    public int hwnd;  
    public int wHitTestCode;  
    public int dwExtraInfo;  
}  

//Declare wrapper managed KeyboardHookStruct class.  
[StructLayout(LayoutKind.Sequential)]  
public class KeyboardHookStruct  
{  
    public int vkCode; //Specifies a virtual-key code. The code must be a value in the range 1 to 254.   
    public int scanCode; // Specifies a hardware scan code for the key.   
    public int flags; // Specifies the extended-key flag, event-injected flag, context code, and transition-state flag.  
    public int time; // Specifies the time stamp for this message.  
    public int dwExtraInfo; // Specifies extra information associated with the message.   
}  

private const int WM_MOUSEMOVE = 0x200; 
private const int WM_LBUTTONDOWN = 0x201; 
private const int WM_RBUTTONDOWN = 0x204; 
private const int WM_MBUTTONDOWN = 0x207; 
private const int WM_LBUTTONUP = 0x202; 
private const int WM_RBUTTONUP = 0x205; 
private const int WM_MBUTTONUP = 0x208; 
private const int WM_LBUTTONDBLCLK = 0x203; 
private const int WM_RBUTTONDBLCLK = 0x206; 
private const int WM_MBUTTONDBLCLK = 0x209; 

private int MouseHookProc(int nCode, Int32 wParam, IntPtr lParam)  
{  
    // if ok and someone listens to our events  
    if ((nCode >= 0) && (OnMouseActivity!=null))   
    {  
        MouseButtons button=MouseButtons.None; 
        switch (wParam)  
        {  
            case WM_LBUTTONDOWN:   
            //case WM_LBUTTONUP:   
            //case WM_LBUTTONDBLCLK:   
            button=MouseButtons.Left;  
            break;  
            case WM_RBUTTONDOWN:   
            //case WM_RBUTTONUP:   
            //case WM_RBUTTONDBLCLK:   
            button=MouseButtons.Right;  
            break;  
        }  
        int clickCount=0; 
        if (button!=MouseButtons.None)  
        if (wParam==WM_LBUTTONDBLCLK || wParam==WM_RBUTTONDBLCLK) clickCount=2; 
        else clickCount=1; 

        //Marshall the data from callback.  
        MouseHookStruct MyMouseHookStruct = (MouseHookStruct) Marshal.PtrToStructure(lParam, typeof(MouseHookStruct)); 
        MouseEventArgs e=new MouseEventArgs(  
        button,   
        clickCount,   
        MyMouseHookStruct.pt.x,   
        MyMouseHookStruct.pt.y,   
        0);  
        OnMouseActivity(this, e); 
    }  
    return CallNextHookEx(hMouseHook, nCode, wParam, lParam);  
}  

//没有实现的部分  
using System.Reflection;  
using System.Runtime;  

//在动态加载的AppDomain中绑定一个事件到函数
void LoadDomain()  
{  
    //Set the Application Domain Setup.  
    AppDomainSetup domainSetup = new AppDomainSetup(); 
    domainSetup.ApplicationBase = System.Environment.CurrentDirectory; 

    //Create Domain  
    AppDomain Domain = AppDomain.CreateDomain("RemoteDomain", null, domainSetup); 
    //Add the DotNetHookDll.dll  
    Assembly assembly = Domain.Load("DotNetHookDll"); 

    object asseblyObject = assembly.CreateInstance("DotNetHook.DotNetHookDll"); 

    System.Type DotNetHookDll = asseblyObject.GetType(); 

    EventInfo[] eventInfors = DotNetHookDll.GetEvents() ; 

    eventInfors[0].AddEventHandler(eventInfors[0],MouseEventHandler(MouseMoved));  
    
    //这一句总报错
    AppDomain.Unload(Domain); 
}  

这个函数想做到: 不用工程引入Dll,要动态加载Dll然后动态释放Dll,并动态绑定Dll中的一个Event到Exe中的一个Delegate.
工程

总结

.Net下实现一个全局的Hook或者某个进程的Hook都不是很好写,写的都比较多,在这一点上没有MFC简单,但是.Net下的AppDomain应用程序域,这种先进的安全的概念,即使Dll出了问题,有异常产生,主程序动态释放这个域,主程序还可以继续执行,而MFC动态加载Dll,Dll里的函数有了问题,整个程序就死了。MFC在这点上远比不上.Net。

参考文章

http://www.microsoft.com/china/msdn/library/langtool/vcsharp/csharp05162002.mspx
http://blog.joycode.com/percyboy/

源代码(WindowsXp Sp2 + VC7 下编译通过)

This post is licensed under CC BY 4.0 by the author.