轉載自http://blog.csdn.net/yushiqiang1688/article/details/5209597
最近要做一個進程監控的程序,功能很簡單,就是創建和退出進程的時候,能觸發我們的事件。
首先的第一想法,是Hook ZwCreateProcess,結果調試的時候發現,很多創建進程的動作,並沒有通過這個API執行,所以自然就是沒辦法監控進程的創建,於是回到本質,從創建進程的動作過程來分析,創建新的進程,其大致要經歷以下步驟:
(1)打開可執行文件,以FILE_EXECUTE權限打開;
(2)將可執行文件加載到內存空間;
(3)進程的活動結構將被創建,如(EPROCESS,KPROCESS和PEB結構);
(4)為新創建的進程分配地址空間;
(5)為進程的主線程創建線程活動結構,如(ETHREAD,KTHREAD和TEB結構);
(6)主線程的棧將會被分配;
(7)進程的主線程的上下文將被創建;
(8)通知windows子系統;
以上總結下來,無非有下面幾種辦法獲取進程創建的消息:
(1)HOOK ZeCreateSection,創建虛擬內存塊的時候,根據傳入的文件句柄,獲取句柄對應的文件名是否為exe可執行文件;
(2)Hook NtReadVirtualMemory,為新創建的進程分配地址空間等操作時,需要讀取進程空間,這樣捕獲,就能夠獲取進程的創建動作;
(3)通過windows提供的回調函數,注冊回調事件;
方法對比:
(1)該方法能夠准確的獲取進程創建的操作,但是由於此時進程並沒有創建完畢,一些進程的基本結構還沒有創建,所以進程ID等信息無法獲取;
(2)該方法能夠獲取進程的創建操作,但不准確。因為除了進程的創建會調用此操作外,人為的一些操作,例如某外部應用程序想讀取另一個進程的內存空間,也會調用這個函數,這時候也會有事件響應,因此結果不准確;
(3)第三種方法更直觀和簡單。因為采用的回調事件,並不直接HOOK API,因此更穩定。
重點分析第三種回調方法。
注冊回調事件,是通過PsSetCreateProcessNotifyRoutine來實現的,其函數原型如下:
NTSTATUS PsSetCreateProcessNotifyRoutine(
IN PCREATE_PROCESS_NOTIFY_ROUTINE NotifyRoutine,
IN BOOLEAN Remove
);
NotifyRoutine就是注冊的回調函數,當有進程創建的時候,就會調用這個NotifyRoutine對應的函數,其函數定義原型如下:
VOID (*PCREATE_PROCESS_NOTIFY_ROUTINE) (
IN HANDLE ParentId,
IN HANDLE ProcessId,
IN BOOLEAN Create
);
其中,ParentId是父進程ID,ProcessId為子進程ID,而Create表示是創建進程還是結束進程,其中True表示創建進程,False表示結束進程。
通過這個函數,我們就能夠完成進程創建和退出的監控,首先調用PsSetCreateProcessNotifyRoutine注冊進程監控回調函數,然后在回調函數里面,判斷Create參數,分別處理進程創建和退出操作。
其它類似的函數還有PsSetLoadImageNotifyRoutine,PsSetCreateThreadNotifyRoutine等。