安全矩阵

 找回密码
 立即注册
搜索
查看: 2250|回复: 0

网络安全编程:行为监控HIPS

[复制链接]

855

主题

862

帖子

2940

积分

金牌会员

Rank: 6Rank: 6

积分
2940
发表于 2021-6-15 09:30:34 | 显示全部楼层 |阅读模式
原文链接:网络安全编程:行为监控HIPS
现在有一种流行的防病毒软件被称作HIPS,中文名字为主机入侵防御系统,比如EQ。该软件可以在进程创建时、有进程对注册表进行写入时或有驱动被加载时,给用户予以选择,选择是否拦截进程的创建、是否拦截注册表的写入、是否拦截驱动的加载等功能。
HIPS纯粹是以预防为主,比如有陌生的进程在被创建阶段,就可以让用户禁止,这样就避免了特征码查杀的滞后性。对于杀毒软件的特征码查杀而言,如果杀毒软件不更新病毒数据库,那么依赖病毒特征码的杀毒软件就无法查杀新型的病毒,对新型的病毒就成为一个摆设。
行为监控的原理主要就是对相关的关键API函数进行HOOK,比如进程拦截。当一个木马程序要秘密启动的时候,对CreateProcessW()函数进行了HOOK,在进程被创建前,会询问用户是否启动该进程,那么木马的隐秘启动就被暴露出来了。对于没有安全知识的大众来说,使用HIPS可能有点困难,也许仍然会让木马运行。因为不是每个使用计算机的人都对计算机有所了解,计算机对于他们而言可能只用来打游戏或看电影。这该如何做呢?现在通常使用的方法就是使用白库和黑库,也就是所谓的白名单和黑名单。在进程被创建时,把要创建的进程到黑白库中去匹配,然后做相应的动作,或者放行,或者拦截。
下面来实现一个应用层下的简单的进程防火墙、注册表防火墙的功能。
1. 简单进程防火墙
进程防火墙指的是放行/拦截准备要创建的进程。进程的创建是依靠CreateProcessW()函数完成的。只要HOOK CreateProcessW()函数就可以实现进程防火墙的功能。对于注册表来说,要对非法进程进行删除或写入注册表键值进行管控,因此需要HOOK两个注册表函数,分别是注册表写入函数RegSetValueExW()和注册表删除函数RegDeleteValueW()。由于使用了HOOK,那么就必然要涉及DLL的编写。这里分DLL和EXE两部分来进行详细的介绍。
2. 实现HOOK部分的DLL程序的编写
因为要对目标进程进行HOOK,因此要编写DLL程序。创建一个DLL程序,并加入已封装的ILHook.h头文件和ILHook.cpp的实现文件。
为了能在所有的基于消息的进程中注入自己的DLL,必须使用Windows钩子,这样就可以将DLL轻易地注入基于消息的进程中。代码如下:
  1. #pragma data_seg(".shared")
  2. HHOOK g_hHook = NULL;
  3. #pragma data_seg()
  4. #pragma comment (linker, ".shared, RWS")
  5. extern "C" __declspec(dllexport) VOID SetHookOn(HWND hWnd);
  6. extern "C" __declspec(dllexport) VOID SetHookOff();
  7. HWND g_ExeHwnd = NULL;
  8. LRESULT CALLBACK GetMsgProc(
  9. int code, // 钩子编码
  10. WPARAM wParam, // 移除选项
  11. LPARAM lParam // 消息
  12. )
  13. {
  14. return CallNextHookEx(g_hHook, code, wParam, lParam);
  15. }
  16. VOID SetHookOn(HWND hWnd)
  17. {
  18. g_ExeHwnd = hWnd;
  19. SetWindowsHookEx(WH_GETMESSAGE, GetMsgProc, g_hInst, 0);
  20. }
  21. VOID SetHookOff()
  22. {
  23. UnhookWindowsHookEx(g_hHook);
  24. g_hHook = NULL;
  25. }
复制代码

以上函数用来定义导出函数,用于加载完成HOOK功能的DLL文件。这里利用WH_ GETMESSAGE钩子类型。
定义3个CILHook类的对象,分别用来对CreateProcessW()函数、RegSetValueExW()函数和RegDeleteValueW()函数进行挂钩。具体定义如下:
  1. CILHook RegSetValueExWHook;
  2. CILHook CreateProcessWHook;
  3. CILHook RegDeleteValueWHook;
复制代码
HOOK部分是在DllMain()函数中完成的,具体代码如下:
  1. BOOL APIENTRY DllMain( HANDLE hModule,
  2.   DWORD ul_reason_for_call,LPVOID lpReserved)
  3. {
  4.   switch ( ul_reason_for_call )
  5.   {
  6.     case DLL_PROCESS_ATTACH:
  7.       {
  8.         g_hInst = (HINSTANCE)hModule;
  9.         RegSetValueExWHook.Hook("advapi32.dll",
  10.           "RegSetValueExW",(PROC)MyRegSetValueExA);
  11.         RegDeleteValueWHook.Hook("advapi32.dll",
  12.           "RegDeleteValueW",(PROC)MyRegDeleteValueW);
  13.         CreateProcessWHook.Hook("kernel32.dll",
  14.           "CreateProcessW",(PROC)MyCreateProcessW);
  15.         break;
  16.       }
  17.     case DLL_PROCESS_DETACH:
  18.       {
  19.         RegSetValueExWHook.UnHook();
  20.         RegDeleteValueWHook.UnHook();
  21.         CreateProcessWHook.UnHook();
  22.         if ( g_hHook != NULL )
  23.         {
  24.           SetHookOff();
  25.         }
  26.         break;
  27.      }
  28.   }
  29.   return TRUE;
  30. }
复制代码
放行/拦截部分是给用户选择的,那么就要给出提示让用户进行选择,至少要给出放行/拦截的类型,比如是注册表写入或是进程的创建,还要给出是哪个进程进行的操作。要把这个信息反馈给用户,这里定义一个结构体,将该结构体的信息发送给用于加载DLL的EXE文件,并让EXE给出提示。结构体定义如下:
  1. typedef struct _HIPS_INFO
  2. {
  3. WCHAR wProcessName[0x200];
  4. DWORD dwHipsClass;
  5. }HIPS_INFO, *PHIPS_INFO;
复制代码

定义一些常量用来标识放行/拦截的类型,具体如下:
  1. #define HIPS_CREATEPROCESS 0x00000001L
  2. #define HIPS_REGSETVALUE 0x00000002L
  3. #define HIPS_REGDELETEVALUE 0x00000003L
复制代码
将这些定义好以后,就可以开始完成HOOK函数了。这里主要给出CreateProcessW()函数的HOOK实现。其余两个函数的HOOK实现,请大家自行实现。具体代码如下:
  1. BOOL
  2. WINAPI
  3. MyCreateProcessW(
  4.   __in_opt LPCWSTR lpApplicationName,
  5.   __inout_opt LPWSTR lpCommandLine,
  6.   __in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes,
  7.   __in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes,
  8.   __in BOOL bInheritHandles,
  9.   __in DWORD dwCreationFlags,
  10.   __in_opt LPVOID lpEnvironment,
  11.   __in_opt LPCWSTR lpCurrentDirectory,
  12.   __in LPSTARTUPINFOW lpStartupInfo,
  13.   __out LPPROCESS_INFORMATION lpProcessInformation
  14.   )
  15. {
  16.   HIPS_INFO sz = { 0 };
  17.   if ( wcslen(lpCommandLine) != 0 )
  18.   {
  19.     wcscpy(sz.wProcessName, lpCommandLine);
  20.   }
  21.   else
  22.   {
  23.     wcscpy(sz.wProcessName, lpApplicationName);
  24.   }
  25.   sz.dwHipsClass = HIPS_CREATEPROCESS;
  26.   COPYDATASTRUCT cds = { NULL, sizeof(HIPS_INFO), (void *)&sz };
  27.   BOOL bRet = FALSE;
  28.   if ( SendMessage(FindWindow(NULL, "Easy Hips For R3"),
  29.     WM_COPYDATA,GetCurrentProcessId(),(LPARAM)&cds) != -1 )
  30.   {
  31.     CreateProcessWHook.UnHook();
  32.     bRet = CreateProcessW(lpApplicationName, lpCommandLine,
  33.       lpProcessAttributes, lpThreadAttributes,
  34.       bInheritHandles, dwCreationFlags,
  35.       lpEnvironment, lpCurrentDirectory,
  36.       lpStartupInfo, lpProcessInformation);
  37.     CreateProcessWHook.ReHook();
  38.   }
  39.   return bRet;
  40. }
复制代码

这里使用了一个SendMessage()函数,该函数用来发送一个WM_COPYDATA消息,将结构体传给了加载DLL的EXE程序,使EXE程序把提示显示给用户。
SendMessage()函数的功能非常强大,其定义如下:
  1. LRESULT SendMessage(
  2. HWND hWnd,
  3. UINT Msg,
  4. WPARAM wParam,
  5. LPARAM lParam
  6. );
复制代码

该函数的第一个参数是目标窗口的句柄,第二个参数是消息类型,最后两个参数是消息的附加参数,根据消息类型的不同而不同。

以上代码就是DLL程序的全部了,剩下两个对注册表操作的HOOK函数,由大家自己完成。

3. 行为监控前台程序的编写

先来看一下程序能达到的效果,再讲解程序EXE部分的实现代码,如图1和图2所示。

图1  程序主界面


图2  拦截提示框

从上面两个图可以看出,程序的确是可以拦截进程的启动的。当单击“允许”按钮后,进程会被正常创建;当单击“取消”按钮后,进程将被阻止创建。这就是最终要完成的功能,来看看主要的实现代码。

EXE的部分主要就是如何来启动行为监控功能,以及如何接收DLL程序通过SendMessage()函数发出的消息给用户弹出提示框。进行拦截的部分已经在DLL程序中通过HOOK实现了,所以重点也就在界面上和消息的接收上。

先看如何启动和停止行为的监控。具体代码如下:
  1. typedef VOID (*SETHOOKON)(HWND);
  2. typedef VOID (*SETHOOKOFF)();
  3. void CHipsDlg::OnBtnOn()
  4. {
  5.   在此处添加处理程序的代码
  6.   m_hInst = LoadLibrary("EasyHips.dll");
  7.   SETHOOKON SetHookOn = (SETHOOKON)GetProcAddress(m_hInst, "SetHookOn");
  8.   SetHookOn(GetSafeHwnd());
  9.   FreeLibrary(m_hInst);
  10.   m_BtnOn.EnableWindow(FALSE);
  11.   m_BtnOff.EnableWindow(TRUE);
  12. }
  13. void CHipsDlg::OnBtnOff()
  14. {
  15.   在此处添加处理程序的代码
  16.   m_hInst = GetModuleHandle("EasyHips.dll");
  17.   SETHOOKOFF SetHookOff = (SETHOOKOFF)GetProcAddress(m_hInst, "SetHookOff");
  18.   SetHookOff();
  19.   CloseHandle(m_hInst);
  20.   FreeLibrary(m_hInst);
  21.   m_BtnOn.EnableWindow(TRUE);
  22.   m_BtnOff.EnableWindow(FALSE);
  23. }
复制代码

从代码中不难看出,直接调用了DLL的两个导出函数,就可以开启自己的打开。在关闭时为什么调用了CloseHandle()函数和FreeLibrary()函数呢?把FreeLibrary()函数去掉,然后单击“停止”监控行为,但还是处在被监控的状态下。因为恢复Inline Hook是在DLL被卸载的情况。因此,在卸载时,调用GetModuleHandle()获得本进程的DLL句柄后,虽然CloseHandle()了,但是只是减少了对DLL的引用计数,并没有真正释放,必须再次使用FreeLibrary()函数才可以使DLL被卸载,从而恢复Inline Hook。
EXE程序接收DLL消息的代码如下:
  1. BOOL CHipsDlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct)
  2. {
  3.   // 在此处添加处理程序的代码
  4.   CTips Tips;
  5.   PHIPS_INFO pHipsInfo = (PHIPS_INFO)pCopyDataStruct->lpData;
  6.   wcscpy(Tips.sz, pHipsInfo->wProcessName);
  7.   Tips.DoModal();
  8.   int nNum = m_HipsReports.GetItemCount();
  9.   CString Str;
  10.   Str.Format("%d", nNum);
  11.   m_HipsReports.InsertItem(nNum, Str);
  12.   SYSTEMTIME StTime;
  13.   GetLocalTime(&StTime);
  14.   Str.Format("%04d/%02d/%02d %02d:%02d:%02d",
  15.     StTime.wYear,StTime.wMonth,StTime.wDay,
  16.     StTime.wHour,StTime.wMonth,StTime.wSecond);
  17.   m_HipsReports.SetItemText(nNum, 1, Str);
  18.   Str.Format("%S", Tips.sz);
  19.   m_HipsReports.SetItemText(nNum, 2, Str);
  20.   switch ( pHipsInfo->dwHipsClass )
  21.   {
  22.     case HIPS_CREATEPROCESS:
  23.       {
  24.         Str = "进程创建";
  25.         break;
  26.       }
  27.     case HIPS_REGSETVALUE:
  28.       {
  29.         break;
  30.       }
  31.     case HIPS_REGDELETEVALUE:
  32.       {
  33.         break;
  34.       }
  35.     }
  36.     m_HipsReports.SetItemText(nNum, 3, Str);
  37.     Str.Format("%s", Tips.bRet ? "放行" : "拦截");
  38.     m_HipsReports.SetItemText(nNum, 4, Str);
  39.   if ( Tips.bRet )
  40.   {
  41.     return 0;
  42.   }
  43.   else
  44.   {
  45.     return -1;
  46.   }
  47.   return CDialog::OnCopyData(pWnd, pCopyDataStruct);
  48. }
复制代码
这部分代码就是对WM_COPYDATA消息的一个响应,整个代码基本是对界面进行了操作。在代码中有一个CTips类的对象,这个类是用来自定义窗口的。该窗口就是用来提示放行和拦截的窗口,其主要代码如下:
  1. void CTips::OnBtnOk()
  2. {
  3.   // 在此处添加处理程序的代码
  4.   bRet = TRUE;
  5.   EndDialog(0);
  6. }
  7. void CTips::OnBtnCancel()
  8. {
  9.   // 在此处添加处理程序的代码
  10.   bRet = FALSE;
  11.   EndDialog(0);
  12. }
复制代码

DLL程序中的SendMessage()函数的返回要等待WM_COPYDATA的消息结束,并从中获得返回值来决定下一步是否执行,因此这里只要简单地返回TRUE或FALSE即可。
对于行为监控就介绍这么多。这个例子演示了如何通过Inline Hook达到对进程创建、注册表操作的管控。当然,这里的代码并不能管控所有的进程,而且这里的行为监控过于简单,很容易被恶意程序突破。这里主要是通过实例来完成对行为监控原理的介绍,希望可以起到抛砖引玉的作用。






回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2024-11-29 10:57 , Processed in 0.012757 second(s), 18 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表