現(xiàn)在有一種流行的防病毒軟件被稱作HIPS,中文名字為主機(jī)入侵防御系統(tǒng),比如EQ。該軟件可以在進(jìn)程創(chuàng)建時(shí)、有進(jìn)程對(duì)注冊(cè)表進(jìn)行寫入時(shí)或有驅(qū)動(dòng)被加載時(shí),給用戶予以選擇,選擇是否攔截進(jìn)程的創(chuàng)建、是否攔截注冊(cè)表的寫入、是否攔截驅(qū)動(dòng)的加載等功能。
HIPS純粹是以預(yù)防為主,比如有陌生的進(jìn)程在被創(chuàng)建階段,就可以讓用戶禁止,這樣就避免了特征碼查殺的滯后性。對(duì)于殺毒軟件的特征碼查殺而言,如果殺毒軟件不更新病毒數(shù)據(jù)庫,那么依賴病毒特征碼的殺毒軟件就無法查殺新型的病毒,對(duì)新型的病毒就成為一個(gè)擺設(shè)。
行為監(jiān)控的原理主要就是對(duì)相關(guān)的關(guān)鍵API函數(shù)進(jìn)行HOOK,比如進(jìn)程攔截。當(dāng)一個(gè)木馬程序要秘密啟動(dòng)的時(shí)候,對(duì)CreateProcessW()函數(shù)進(jìn)行了HOOK,在進(jìn)程被創(chuàng)建前,會(huì)詢問用戶是否啟動(dòng)該進(jìn)程,那么木馬的隱秘啟動(dòng)就被暴露出來了。對(duì)于沒有安全知識(shí)的大眾來說,使用HIPS可能有點(diǎn)困難,也許仍然會(huì)讓木馬運(yùn)行。因?yàn)椴皇敲總€(gè)使用計(jì)算機(jī)的人都對(duì)計(jì)算機(jī)有所了解,計(jì)算機(jī)對(duì)于他們而言可能只用來打游戲或看電影。這該如何做呢?現(xiàn)在通常使用的方法就是使用白庫和黑庫,也就是所謂的白名單和黑名單。在進(jìn)程被創(chuàng)建時(shí),把要?jiǎng)?chuàng)建的進(jìn)程到黑白庫中去匹配,然后做相應(yīng)的動(dòng)作,或者放行,或者攔截。
下面來實(shí)現(xiàn)一個(gè)應(yīng)用層下的簡(jiǎn)單的進(jìn)程防火墻、注冊(cè)表防火墻的功能。
1. 簡(jiǎn)單進(jìn)程防火墻
進(jìn)程防火墻指的是放行/攔截準(zhǔn)備要?jiǎng)?chuàng)建的進(jìn)程。進(jìn)程的創(chuàng)建是依靠CreateProcessW()函數(shù)完成的。只要HOOK CreateProcessW()函數(shù)就可以實(shí)現(xiàn)進(jìn)程防火墻的功能。對(duì)于注冊(cè)表來說,要對(duì)非法進(jìn)程進(jìn)行刪除或?qū)懭胱?cè)表鍵值進(jìn)行管控,因此需要HOOK兩個(gè)注冊(cè)表函數(shù),分別是注冊(cè)表寫入函數(shù)RegSetValueExW()和注冊(cè)表刪除函數(shù)RegDeleteValueW()。由于使用了HOOK,那么就必然要涉及DLL的編寫。這里分DLL和EXE兩部分來進(jìn)行詳細(xì)的介紹。
2. 實(shí)現(xiàn)HOOK部分的DLL程序的編寫
因?yàn)橐獙?duì)目標(biāo)進(jìn)程進(jìn)行HOOK,因此要編寫DLL程序。創(chuàng)建一個(gè)DLL程序,并加入已封裝的ILHook.h頭文件和ILHook.cpp的實(shí)現(xiàn)文件。
為了能在所有的基于消息的進(jìn)程中注入自己的DLL,必須使用Windows鉤子,這樣就可以將DLL輕易地注入基于消息的進(jìn)程中。代碼如下:
#pragma data_seg(“.shared”)
HHOOK g_hHook = NULL;
#pragma data_seg()
#pragma comment (linker, “.shared, RWS”)
extern “C” __declspec(dllexport) VOID SetHookOn(HWND hWnd);
extern “C” __declspec(dllexport) VOID SetHookOff();
HWND g_ExeHwnd = NULL;
LRESULT CALLBACK GetMsgProc(
int code, // 鉤子編碼
WPARAM wParam, // 移除選項(xiàng)
LPARAM lParam // 消息
?。?/p>
{
return CallNextHookEx(g_hHook, code, wParam, lParam);
}
VOID SetHookOn(HWND hWnd)
{
g_ExeHwnd = hWnd;
SetWindowsHookEx(WH_GETMESSAGE, GetMsgProc, g_hInst, 0);
}
VOID SetHookOff()
{
UnhookWindowsHookEx(g_hHook);
g_hHook = NULL;
}
以上函數(shù)用來定義導(dǎo)出函數(shù),用于加載完成HOOK功能的DLL文件。這里利用WH_ GETMESSAGE鉤子類型。
定義3個(gè)CILHook類的對(duì)象,分別用來對(duì)CreateProcessW()函數(shù)、RegSetValueExW()函數(shù)和RegDeleteValueW()函數(shù)進(jìn)行掛鉤。具體定義如下:
CILHook RegSetValueExWHook;
CILHook CreateProcessWHook;
CILHook RegDeleteValueWHook;
HOOK部分是在DllMain()函數(shù)中完成的,具體代碼如下:
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,LPVOID lpReserved)
{
switch ( ul_reason_for_call )
{
case DLL_PROCESS_ATTACH:
{
g_hInst = (HINSTANCE)hModule;
RegSetValueExWHook.Hook(“advapi32.dll”,
“RegSetValueExW”,(PROC)MyRegSetValueExA);
RegDeleteValueWHook.Hook(“advapi32.dll”,
“RegDeleteValueW”,(PROC)MyRegDeleteValueW);
CreateProcessWHook.Hook(“kernel32.dll”,
“CreateProcessW”,(PROC)MyCreateProcessW);
break;
}
case DLL_PROCESS_DETACH:
{
RegSetValueExWHook.UnHook();
RegDeleteValueWHook.UnHook();
CreateProcessWHook.UnHook();
if ( g_hHook != NULL )
{
SetHookOff();
}
break;
}
}
return TRUE;
}
放行/攔截部分是給用戶選擇的,那么就要給出提示讓用戶進(jìn)行選擇,至少要給出放行/攔截的類型,比如是注冊(cè)表寫入或是進(jìn)程的創(chuàng)建,還要給出是哪個(gè)進(jìn)程進(jìn)行的操作。要把這個(gè)信息反饋給用戶,這里定義一個(gè)結(jié)構(gòu)體,將該結(jié)構(gòu)體的信息發(fā)送給用于加載DLL的EXE文件,并讓EXE給出提示。結(jié)構(gòu)體定義如下:
typedef struct _HIPS_INFO
{
WCHAR wProcessName[0x200];
DWORD dwHipsClass;
}HIPS_INFO, *PHIPS_INFO;
定義一些常量用來標(biāo)識(shí)放行/攔截的類型,具體如下:
#define HIPS_CREATEPROCESS 0x00000001L
#define HIPS_REGSETVALUE 0x00000002L
#define HIPS_REGDELETEVALUE 0x00000003L
將這些定義好以后,就可以開始完成HOOK函數(shù)了。這里主要給出CreateProcessW()函數(shù)的HOOK實(shí)現(xiàn)。其余兩個(gè)函數(shù)的HOOK實(shí)現(xiàn),請(qǐng)大家自行實(shí)現(xiàn)。具體代碼如下:
BOOL
WINAPI
MyCreateProcessW(
__in_opt LPCWSTR lpApplicationName,
__inout_opt LPWSTR lpCommandLine,
__in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes,
__in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes,
__in BOOL bInheritHandles,
__in DWORD dwCreationFlags,
__in_opt LPVOID lpEnvironment,
__in_opt LPCWSTR lpCurrentDirectory,
__in LPSTARTUPINFOW lpStartupInfo,
__out LPPROCESS_INFORMATION lpProcessInformation
)
{
HIPS_INFO sz = { 0 };
if ( wcslen(lpCommandLine) != 0 )
{
wcscpy(sz.wProcessName, lpCommandLine);
}
else
{
wcscpy(sz.wProcessName, lpApplicationName);
}
sz.dwHipsClass = HIPS_CREATEPROCESS;
COPYDATASTRUCT cds = { NULL, sizeof(HIPS_INFO), (void *)&sz };
BOOL bRet = FALSE;
if ( SendMessage(FindWindow(NULL, “Easy Hips For R3”),
WM_COPYDATA,GetCurrentProcessId(),(LPARAM)&cds) != -1 )
{
CreateProcessWHook.UnHook();
bRet = CreateProcessW(lpApplicationName, lpCommandLine,
lpProcessAttributes, lpThreadAttributes,
bInheritHandles, dwCreationFlags,
lpEnvironment, lpCurrentDirectory,
lpStartupInfo, lpProcessInformation);
CreateProcessWHook.ReHook();
}
return bRet;
}
這里使用了一個(gè)SendMessage()函數(shù),該函數(shù)用來發(fā)送一個(gè)WM_COPYDATA消息,將結(jié)構(gòu)體傳給了加載DLL的EXE程序,使EXE程序把提示顯示給用戶。
SendMessage()函數(shù)的功能非常強(qiáng)大,其定義如下:
LRESULT SendMessage(
HWND hWnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam
?。?;
該函數(shù)的第一個(gè)參數(shù)是目標(biāo)窗口的句柄,第二個(gè)參數(shù)是消息類型,最后兩個(gè)參數(shù)是消息的附加參數(shù),根據(jù)消息類型的不同而不同。
以上代碼就是DLL程序的全部了,剩下兩個(gè)對(duì)注冊(cè)表操作的HOOK函數(shù),由大家自己完成。
3. 行為監(jiān)控前臺(tái)程序的編寫
先來看一下程序能達(dá)到的效果,再講解程序EXE部分的實(shí)現(xiàn)代碼,如圖1和圖2所示。
圖1 程序主界面
圖2 攔截提示框
從上面兩個(gè)圖可以看出,程序的確是可以攔截進(jìn)程的啟動(dòng)的。當(dāng)單擊“允許”按鈕后,進(jìn)程會(huì)被正常創(chuàng)建;當(dāng)單擊“取消”按鈕后,進(jìn)程將被阻止創(chuàng)建。這就是最終要完成的功能,來看看主要的實(shí)現(xiàn)代碼。
EXE的部分主要就是如何來啟動(dòng)行為監(jiān)控功能,以及如何接收DLL程序通過SendMessage()函數(shù)發(fā)出的消息給用戶彈出提示框。進(jìn)行攔截的部分已經(jīng)在DLL程序中通過HOOK實(shí)現(xiàn)了,所以重點(diǎn)也就在界面上和消息的接收上。
先看如何啟動(dòng)和停止行為的監(jiān)控。具體代碼如下:
typedef VOID (*SETHOOKON)(HWND);
typedef VOID (*SETHOOKOFF)();
void CHipsDlg::OnBtnOn()
{
在此處添加處理程序的代碼
m_hInst = LoadLibrary(“EasyHips.dll”);
SETHOOKON SetHookOn = (SETHOOKON)GetProcAddress(m_hInst, “SetHookOn”);
SetHookOn(GetSafeHwnd());
FreeLibrary(m_hInst);
m_BtnOn.EnableWindow(FALSE);
m_BtnOff.EnableWindow(TRUE);
}
void CHipsDlg::OnBtnOff()
{
在此處添加處理程序的代碼
m_hInst = GetModuleHandle(“EasyHips.dll”);
SETHOOKOFF SetHookOff = (SETHOOKOFF)GetProcAddress(m_hInst, “SetHookOff”);
SetHookOff();
CloseHandle(m_hInst);
FreeLibrary(m_hInst);
m_BtnOn.EnableWindow(TRUE);
m_BtnOff.EnableWindow(FALSE);
}
從代碼中不難看出,直接調(diào)用了DLL的兩個(gè)導(dǎo)出函數(shù),就可以開啟自己的打開。在關(guān)閉時(shí)為什么調(diào)用了CloseHandle()函數(shù)和FreeLibrary()函數(shù)呢?把FreeLibrary()函數(shù)去掉,然后單擊“停止”監(jiān)控行為,但還是處在被監(jiān)控的狀態(tài)下。因?yàn)榛謴?fù)Inline Hook是在DLL被卸載的情況。因此,在卸載時(shí),調(diào)用GetModuleHandle()獲得本進(jìn)程的DLL句柄后,雖然CloseHandle()了,但是只是減少了對(duì)DLL的引用計(jì)數(shù),并沒有真正釋放,必須再次使用FreeLibrary()函數(shù)才可以使DLL被卸載,從而恢復(fù)Inline Hook。
EXE程序接收DLL消息的代碼如下:
BOOL CHipsDlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct)
{
// 在此處添加處理程序的代碼
CTips Tips;
PHIPS_INFO pHipsInfo = (PHIPS_INFO)pCopyDataStruct->lpData;
wcscpy(Tips.sz, pHipsInfo->wProcessName);
Tips.DoModal();
int nNum = m_HipsReports.GetItemCount();
CString Str;
Str.Format(“%d”, nNum);
m_HipsReports.InsertItem(nNum, Str);
SYSTEMTIME StTime;
GetLocalTime(&StTime);
Str.Format(“%04d/%02d/%02d %02d:%02d:%02d”,
StTime.wYear,StTime.wMonth,StTime.wDay,
StTime.wHour,StTime.wMonth,StTime.wSecond);
m_HipsReports.SetItemText(nNum, 1, Str);
Str.Format(“%S”, Tips.sz);
m_HipsReports.SetItemText(nNum, 2, Str);
switch ( pHipsInfo->dwHipsClass )
{
case HIPS_CREATEPROCESS:
{
Str = “進(jìn)程創(chuàng)建”;
break;
}
case HIPS_REGSETVALUE:
{
break;
}
case HIPS_REGDELETEVALUE:
{
break;
}
}
m_HipsReports.SetItemText(nNum, 3, Str);
Str.Format(“%s”, Tips.bRet ? “放行” : “攔截”);
m_HipsReports.SetItemText(nNum, 4, Str);
if ( Tips.bRet )
{
return 0;
}
else
{
return -1;
}
return CDialog::OnCopyData(pWnd, pCopyDataStruct);
}
這部分代碼就是對(duì)WM_COPYDATA消息的一個(gè)響應(yīng),整個(gè)代碼基本是對(duì)界面進(jìn)行了操作。在代碼中有一個(gè)CTips類的對(duì)象,這個(gè)類是用來自定義窗口的。該窗口就是用來提示放行和攔截的窗口,其主要代碼如下:
void CTips::OnBtnOk()
{
// 在此處添加處理程序的代碼
bRet = TRUE;
EndDialog(0);
}
void CTips::OnBtnCancel()
{
// 在此處添加處理程序的代碼
bRet = FALSE;
EndDialog(0);
}
DLL程序中的SendMessage()函數(shù)的返回要等待WM_COPYDATA的消息結(jié)束,并從中獲得返回值來決定下一步是否執(zhí)行,因此這里只要簡(jiǎn)單地返回TRUE或FALSE即可。
對(duì)于行為監(jiān)控就介紹這么多。這個(gè)例子演示了如何通過Inline Hook達(dá)到對(duì)進(jìn)程創(chuàng)建、注冊(cè)表操作的管控。當(dāng)然,這里的代碼并不能管控所有的進(jìn)程,而且這里的行為監(jiān)控過于簡(jiǎn)單,很容易被惡意程序突破。這里主要是通過實(shí)例來完成對(duì)行為監(jiān)控原理的介紹,希望可以起到拋磚引玉的作用。