病毒檢測與防毒技術大揭祕8
3.4.自我保護設計方案及編碼實現
實現此功能,同樣使用API Hook技術,與上面介紹過的病毒防護功能類似。只是這裡不再是攔截CreateProcess,而是要接管OpenProcess函式。
也許有的程式設計師朋友會有疑惑,做我我保護,也就是要防止自己的程序被非法結束程序,在程式設計中,結束程序所使用API函式是TerminateProcess,而不是OpenProcess,這裡為什麼會說通過攔截OpenProcess實現保護程序呢?這是由於TerminateProcess函式結束程序時,需要使用程序控制代碼做為輸入引數,結束傳入的指定控制代碼的程序。但在不同程序間控制代碼是無法傳遞的,因為即便是同一個檔案,在每個不同的程序中都會為它分配不同的控制代碼。好在程序ID是可以傳遞的,而在使用TerminateProcess函式結束程序前,會先呼叫OpenProcess開啟程序並把控制代碼傳遞給TerminateProcess,而OpenProcess函式的輸入引數恰好為程序ID。這也就是我們選擇攔截OpenProcess的原因了。
防止被結束程序的原理很簡單,將DLL注入其它程序後,接管程序的OpenProcess函式,在我們自己定義的新OpenProcess函式被呼叫時,判斷是否要開啟我們防毒軟體的程序,並且其操作是否是要將要程序結束程序操作,如果是,就終止這個行為。這樣便實現了保護,做到了程序防殺。
且看編碼實現,首先是DLL中攔截OpenProcess的部分。鑑於上文中又詳細介紹過攔截CreateProcess函式的方法,這裡就不再重複對程式碼做說明了,參考上文程式碼中的註釋說明即可。
#include <windows.h> #include "stdio.h" #include "stdlib.h" #pragma data_seg(".Shared2") static DWORD g_PID2Protect=0; #pragma data_seg() #pragma comment(linker, "/section:.Shared2,rws") HANDLE hProcess=0; UCHAR OldCode2[5]={0}, NewCode2[5]={0}; ULONG FunAddr2=0; HINSTANCE hMod=0; HHOOK hHook=0; BOOL HookStatus2(BOOL Status){ BOOL ret2=FALSE; if (Status) { ret2 = WriteProcessMemory(hProcess, (void *)FunAddr2, NewCode2, 5, 0); if (ret2) return TRUE;} else { ret2 = WriteProcessMemory(hProcess, (void *)FunAddr2, OldCode2, 5, 0); if (ret2) return TRUE;} return FALSE; } HANDLE WINAPI OpenProcessCallBack(DWORD dwDesiredAccess,BOOL bInheritHandle,DWORD dwProcessId) { HANDLE hProc=NULL; if(dwProcessId==g_PID2Protect && (dwDesiredAccess & PROCESS_TERMINATE!=0)) { hProc=NULL; }else{ HookStatus2(FALSE); hProc= OpenProcess(dwDesiredAccess,bInheritHandle,dwProcessId); HookStatus2(TRUE); } return hProc; } BOOL HookOpenProcess(){ ULONG JmpAddr2=0; FunAddr2 = (ULONG)GetProcAddress(LoadLibrary("Kernel32.dll"), "OpenProcess"); memcpy(OldCode2, (void *)FunAddr2, 5); NewCode2[0] = 0xe9; JmpAddr2 = (ULONG)OpenProcessCallBack - FunAddr2 - 5; memcpy(&NewCode2[1], &JmpAddr2, 4); HookStatus2(TRUE); return TRUE; } BOOL APIENTRY DllMain( HANDLE hModule,DWORD ul_reason_for_call, LPVOID lpReserved) { hMod = (HINSTANCE)hModule; if (ul_reason_for_call==DLL_PROCESS_ATTACH) { hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, GetCurrentProcessId()); HookOpenProcess(); } if (ul_reason_for_call==DLL_PROCESS_DETACH) { HookStatus2(FALSE); } return TRUE; } LRESULT CALLBACK HookProc(int nCode,WPARAM wParam,LPARAM lParam){ return(CallNextHookEx(hHook,nCode,wParam,lParam)); } BOOL WINAPI SafeGuardOFF(){ return(UnhookWindowsHookEx(hHook)); } BOOL WINAPI SafeGuardON(DWORD uPID){ g_PID2Protect=uPID; hHook = SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC)HookProc, hMod, 0); if (hHook) { return TRUE; }else{ return FALSE; } }
由程式碼中可知,此DLL的匯出函式有兩個:SafeGuardON和SafeGuardOFF,SafeGuardON用於開啟防護,引數是被保護程序的ID;SafeGuardOFF用於關閉防護。
在上層應用程式中,呼叫方法如下:
函式宣告:
Private Declare Function ActiveDefenseON Lib "ActiveDefense.dll" (ByVal TargetHwnd As Long) As Boolean Private Declare Function ActiveDefenseOFF Lib "ActiveDefense.dll" () As Boolean
DLl中的函式再次封裝為新函式:
Public Function ActiveDefense(ByVal bOperation As Boolean) As Boolean
Dim lPid As Long
獲取當前程序PID,也就是我們防毒軟體的程序ID:
lPid = GetCurrentProcessId
Dim bRet As Boolean If bOperation = True Then
開啟主動防禦:
bRet = ActiveDefenseON(lPid) If bRet Then ActiveDefense = True Else ActiveDefense = False End If Else
關閉主動防禦:
ActiveDefenseOFF End If
End Function
有此簡單封裝過的函式,當防毒軟體啟動時呼叫,傳入引數true便可開啟防護,關閉程式時呼叫傳入false便可停止防護。使用非常簡單。
注:作者:wing qq:6465660 本書理論及功能、程式碼源於防毒軟體:“Ty2y防毒軟體”,作者授意,文章可自由轉載,只需註明原出處即可,特此說明。