首页 > 技术文章 > EasyHook远注简单监控示例 z

zeroone 2014-05-27 11:32 原文

http://www.csdn 123.com/html/itweb/20130827/83559_83558_83544.htm

 

免费开源库EasyHook(inline hook),下面是下载地址

http://easyhook.codeplex.com/releases/view/24401 把头文件 lib文件全拷贝在工程文件夹中,把dll拷贝在%system32%中(PS:

64位 应该放在C:\Windows\SysWOW64文件夹中)

 

好的,现在切入正题。

假设我们的工程是要监控Troj.exe的行为。A.exe为监控应用程序,A.exe先遍历当前进程,若找到Troj.exe则将B.dll远程线程注入到Troj.exe进程中

PS: XP CreateRemoteThread win7用NT系列函数,如下:

 1 typedef DWORD (WINAPI *PFNTCREATETHREADEX)  
 2     (   
 3     OUT PHANDLE             ThreadHandle,     
 4     ACCESS_MASK             DesiredAccess,    
 5     LPVOID                  ObjectAttributes,     
 6     HANDLE                  ProcessHandle,    
 7     LPTHREAD_START_ROUTINE  lpStartAddress,   
 8     LPVOID                  lpParameter,      
 9     BOOL                    CreateSuspended,      
10     DWORD                   dwStackSize,      
11     DWORD                   dw1,   
12     DWORD                   dw2,   
13     LPVOID                  Unknown   
14     );   
15 
16 BOOL IsVistaOrLater()  
17 {  
18     OSVERSIONINFO osvi;  
19     ZeroMemory(&osvi, sizeof(OSVERSIONINFO));  
20     osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);  
21     GetVersionEx(&osvi);  
22     if( osvi.dwMajorVersion >= 6 )  
23     {
24         return TRUE;  
25     }
26     return FALSE;  
27 }  
28 
29 BOOL MyCreateRemoteThread(HANDLE hProcess, LPTHREAD_START_ROUTINE pThreadProc, LPVOID pRemoteBuf)  
30 {  
31     HANDLE      hThread = NULL;  
32     FARPROC     pFunc = NULL;  
33     if( IsVistaOrLater() )    // Vista, 7, Server2008  
34     {  
35         pFunc = GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtCreateThreadEx");  
36         if( pFunc == NULL )  
37         {  
38             ErrorReport(GetLastError()); 
39         }  
40         ((PFNTCREATETHREADEX)pFunc)(&hThread,  
41             0x1FFFFF,  
42             NULL,  
43             hProcess,  
44             pThreadProc,  
45             pRemoteBuf,  
46             FALSE,  
47             NULL,  
48             NULL,  
49             NULL,  
50             NULL);  
51         if( hThread == NULL )  
52         {  
53             ErrorReport(GetLastError());
54         }  
55     }  
56     else                    // 2000, XP, Server2003  
57     {  
58         hThread = CreateRemoteThread(hProcess,   
59             NULL,   
60             0,   
61             pThreadProc,   
62             pRemoteBuf,   
63             0,   
64             NULL);  
65         if( hThread == NULL )  
66         {  
67             ErrorReport(GetLastError()); 
68         }  
69     }  
70     if( WAIT_FAILED == WaitForSingleObject(hThread, INFINITE) )  
71     {  
72         ErrorReport(GetLastError());
73     }  
74     return TRUE;  
75 }   

注入成功后,DLL和A.exe建立命名管道进行进程间通信。例如,当Troj.exe调用CopyFileW被B.dll拦载时,发送相关数据(简称为M结构体)到A.exe文本控件上显示。

M结构体如下构造:

 1 struct WinExec
 2 {
 3     _In_  CHAR lpCmdLine[0x400];
 4     _In_  UINT uCmdShow;
 5 };
 6 
 7 struct CopyFileW
 8 {
 9     _In_  TCHAR lpExistingFileName[0x400];
10     _In_  TCHAR lpNewFileName[0x400];
11     _In_  BOOL bFailIfExists;
12 };
13 
14 typedef struct _tag_info
15 {
16     DWORD time;
17     DWORD Return;
18     DWORD Info_Type;
19 
20     union{
21         struct WinExec WinExec_;
22         struct CopyFileW CopyFileW_;
23     };
24 
25 }taginfo, *ptaginfo;
26 
27 #define WINEXEC_INFO 1
28 #define COPYFILEW 2

 

 

我的这个实例很基础,就拦载Winexec函数和CopyFileW函数

请先允许我展示几个头文件 

 hook.h

 1 #pragma once
 2 
 3 
 4 #ifndef _M_X64
 5 #pragma comment(lib, "EasyHook32.lib")
 6 #else
 7 #pragma comment(lib, "EasyHook64.lib")
 8 #endif
 9 
10 UINT WINAPI MyWinExec(
11     _In_  LPCSTR lpCmdLine,
12     _In_  UINT uCmdShow
13     );
14 
15 typedef UINT (WINAPI * ptrWinExec)(
16     _In_  LPCSTR lpCmdLine,
17     _In_  UINT uCmdShow
18     );
19 
20 extern ptrWinExec realWinExec;
21 
22 BOOL WINAPI MyCopyFileW(
23     _In_  LPCTSTR lpExistingFileName,
24     _In_  LPCTSTR lpNewFileName,
25     _In_  BOOL bFailIfExists
26     );
27 
28 typedef BOOL (WINAPI *ptrCopyFileW)(
29     _In_  LPCTSTR lpExistingFileName,
30     _In_  LPCTSTR lpNewFileName,
31     _In_  BOOL bFailIfExists
32     );
33 
34 extern ptrCopyFileW realCopyFileW;
hook.h

 

 head.h

 1 #include "easyhook.h"  
 2 #include "Hook.h"
 3 #include <Shlwapi.h>
 4 #include <stdio.h>
 5 
 6 #pragma comment(lib, "Shlwapi.lib")
 7 #pragma comment(lib, "winmm.lib")
 8 
 9 ptrWinExec              realWinExec = NULL; //真实地址
10 ptrCopyFileW            realCopyFileW   = NULL;
11 
12 TRACED_HOOK_HANDLE      hHookWinExec = new HOOK_TRACE_INFO();
13 TRACED_HOOK_HANDLE      hHookCopyFileW   = new HOOK_TRACE_INFO();
14 
15 ULONG                   HookWinExec_ACLEntries[1]   = {0};
16 ULONG                   HookCopyFileW_ACLEntries[1]   = {0};
17 
18 HANDLE                  hNamedPipe;//命名管道句柄
19 
20 DWORD StartTime = 0;//应用程序起始时间
21 
22 #define sizeofpipe 0x800 //管道的大小
23 
24 void CreateNamedPipeInServer();//声明函数 部分内容非关键内容没有列出来
25 void ErrorReport(DWORD errorid);
head.h

 

DllMain.cpp

 1 #include "Header.h" 
 2 
 3 int PrepareRealApiEntry()  
 4 {  
 5     HMODULE hKernel32 = LoadLibrary(L"Kernel32.dll");  
 6     if (!(realWinExec = (ptrWinExec)GetProcAddress(hKernel32, "WinExec")) ||
 7         !(realCopyFileW = (ptrCopyFileW)GetProcAddress(hKernel32, "CopyFileW")))
 8     {
 9         ErrorReport(GetLastError());
10     }
11     return 0;
12 } 
13 
14 void DoHook()  
15 {  
16      LhInstallHook(realWinExec, MyWinExec, NULL, hHookWinExec);
17      LhSetExclusiveACL(HookWinExec_ACLEntries, 1, hHookWinExec);
18 
19      LhInstallHook(realCopyFileW,  MyCopyFileW, NULL, hHookCopyFileW);
20      LhSetExclusiveACL(HookCopyFileW_ACLEntries, 1, hHookCopyFileW);
21 }  
22 
23 void DoneHook()  
24 {  
25     // this will also invalidate "hHook", because it is a traced handle...  
26     LhUninstallAllHooks();  
27 
28     // this will do nothing because the hook is already removed...  
29 
30     LhUninstallHook(hHookWinExec);
31     LhUninstallHook(hHookCopyFileW);
32 
33     // now we can safely release the traced handle  
34     delete hHookWinExec;
35     hHookWinExec = NULL;
36 
37     delete hHookCopyFileW;
38     hHookCopyFileW = NULL;
39 
40     // even if the hook is removed, we need to wait for memory release  
41     LhWaitForPendingRemovals();  
42 }  
43 
44 BOOL APIENTRY DllMain( HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved  )  
45 {  
46     switch (ul_reason_for_call)  
47     {  
48     case DLL_PROCESS_ATTACH:  
49         {  
50             StartTime = timeGetTime();
51             CreateNamedPipeInServer(); 
52             if (PrepareRealApiEntry() != 0)  
53             {  
54                 return FALSE;  
55             }  
56             DoHook();  
57 
58             break;  
59         }  
60     case DLL_THREAD_ATTACH:  
61         {  
62             break;  
63         }  
64     case DLL_THREAD_DETACH:  
65         {  
66             break;  
67         }  
68 
69     case DLL_PROCESS_DETACH:  
70         {  
71             DoneHook();  
72             break;  
73         }  
74     }  
75     return TRUE;  
76 }

 

hook_fakefunction.cpp

 1 BOOL WINAPI MyCopyFileW( //Mystery of Panda
 2     _In_  LPCTSTR lpExistingFileName,
 3     _In_  LPCTSTR lpNewFileName,
 4     _In_  BOOL bFailIfExists
 5     )
 6 {
 7     //进入真实函数前,跳转到此处
 8     bool status = false;
 9     status = (realCopyFileW)(lpExistingFileName, lpNewFileName, bFailIfExists);//执行真正的CopyFileW函数
10     ptaginfo tagstruct;//上述M结构体
11     ZeroMemory(tagstruct, sizeof(tagstruct));
12     if (!(tagstruct = (ptaginfo)malloc(sizeof(_tag_info))))
13     {
14         return status;
15     }
16     HANDLE hThread;
17     tagstruct->time = timeGetTime() - StartTime;//填充结构体开始
18     tagstruct->Return = status;
19     tagstruct->Info_Type = COPYFILEW;
20     if (lpExistingFileName != NULL) //检查参数 在实际调试中发现如果不检查参数,DLL可能会崩溃
21     {
22         wcscpy(tagstruct->CopyFileW_.lpExistingFileName, lpExistingFileName);
23     }
24     else
25     {
26         free(tagstruct);
27         return status;
28     }
29     tagstruct->CopyFileW_.bFailIfExists = bFailIfExists;
30     if (lpNewFileName != NULL) //检查参数
31     {
32         wcscpy(tagstruct->CopyFileW_.lpNewFileName, lpNewFileName);
33     }
34     else
35     {
36         free(tagstruct);
37         return status;
38     }
39     //填充结构体完毕
40     hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)WritePipe, (ptaginfo)tagstruct, 0, 0);//创建线程发送数据到管道
41     if (hThread)
42     {
43         WaitForSingleObject(hThread, INFINITE);
44         CloseHandle(hThread);
45     }
46     free(tagstruct);
47     return status;
48 } 49 50 UINT WINAPI MyWinExec( 51 _In_ LPCSTR lpCmdLine, 52 _In_ UINT uCmdShow 53 ) 54 { 55 ... 56 }

 

至此,这个简单监控示例就完成了。

题外话:这只是应用层的最简单的钩子,可以轻易的被绕过。如果在应用层上想做的更深一点,例如监控troj.exe的进程创建,可以考虑钩R3上的NtCreateUserProcess函数,下面是网上逆出来的函数参数

 1 typedef struct _NT_PROC_THREAD_ATTRIBUTE_ENTRY {
 2     ULONG Attribute;    // PROC_THREAD_ATTRIBUTE_XXX,参见MSDN中UpdateProcThreadAttribute的说明
 3     SIZE_T Size;        // Value的大小
 4     ULONG_PTR Value;    // 保存4字节数据(比如一个Handle)或数据指针
 5     ULONG Unknown;      // 总是0,可能是用来返回数据给调用者
 6 } PROC_THREAD_ATTRIBUTE_ENTRY, *PPROC_THREAD_ATTRIBUTE_ENTRY;
 7 
 8 typedef struct _NT_PROC_THREAD_ATTRIBUTE_LIST {
 9     ULONG Length;       // 结构总大小
10     NT_PROC_THREAD_ATTRIBUTE_ENTRY Entry[1];
11 } NT_PROC_THREAD_ATTRIBUTE_LIST, *PNT_PROC_THREAD_ATTRIBUTE_LIST;
12 NTSTATUS NtCreateUserProcess(
13     OUT PHANDLE ProcessHandle,
14     OUT PHANDLE ThreadHandle,
15     IN ACCESS_MASK ProcessDesiredAccess,
16     IN ACCESS_MASK ThreadDesiredAccess,
17     IN POBJECT_ATTRIBUTES ProcessObjectAttributes OPTIONAL,
18     IN POBJECT_ATTRIBUTES ThreadObjectAttributes OPTIONAL,
19     IN ULONG CreateProcessFlags,
20     IN ULONG CreateThreadFlags,
21     IN PRTL_USER_PROCESS_PARAMETERS ProcessParameters,
22     IN PVOID Parameter9,
23     IN PNT_PROC_THREAD_ATTRIBUTE_LIST AttributeList
24 );

不过只能作为统计创建进程数,不能在应用层上得到创建的进程信息(INVALID_HANDLE_VALUE)。

推荐阅读