一、核心程式碼
一共三部分:
- 定義回撥函式
- 註冊回撥
- 移除回撥
#include <ntddk.h>
// 定義回撥函式,在後續實現
VOID ProcessNotifyRoutine(
_Inout_ PEPROCESS Process, // 程序物件,這是個不透明結構,不建議強行使用其中的欄位
_In_ HANDLE ProcessId, // 程序ID
_In_opt_ PPS_CREATE_NOTIFY_INFO CreateInfo // 程序建立資訊
);
// 定義解除安裝函式,在後續實現
NTSTATUS DriverUnload(_In_ PDRIVER_OBJECT DriverObject);
// 在DriverEntry中註冊回撥
NTSTATUS
DriverEntry(
_In_ PDRIVER_OBJECT DriverObject,
_In_ PUNICODE_STRING RegistryPath
)
{
UNREFERENCED_PARAMETER(RegistryPath); // 未使用的引數,需要UNREFERENCED_PARAMETER處理,不然會warning
NTSTATUS status;
// 註冊解除安裝函式
DriverObject->DriverUnload = DriverUnload;
// 註冊程序回撥,第二個參數列示是否移除,true表示移除,false表示註冊
status = PsSetCreateProcessNotifyRoutineEx(ProcessNotifyRoutine, FALSE);
return STATUS_SUCCESS;
}
// 在解除安裝函式中移除回撥
NTSTATUS DriverUnload(_In_ PDRIVER_OBJECT DriverObject)
{
UNREFERENCED_PARAMETER(DriverObject);
NTSTATUS status;
// 移除回撥,第二個參數列示是否移除,true表示移除,false表示註冊
status = PsSetCreateProcessNotifyRoutineEx(ProcessNotifyRoutine, TRUE);
return status;
}
// 程序回撥實現
VOID ProcessNotifyRoutine(
_Inout_ PEPROCESS Process, // 程序物件,這是個不透明結構,不建議強行使用其中的欄位
_In_ HANDLE ProcessId, // 程序ID
_In_opt_ PPS_CREATE_NOTIFY_INFO CreateInfo // 程序建立資訊
)
{
UNREFERENCED_PARAMETER(Process);
UNREFERENCED_PARAMETER(ProcessId);
UNREFERENCED_PARAMETER(CreateInfo);
// 這裡可以記錄程序的建立和銷燬
if (CreateInfo != NULL)
{
// 程序建立
// 如果需要阻止程序建立,則可以
// 設定 CreateInfo 中的 CreationStatus 欄位為 STATUS_ACCESS_DENIED
// CreateInfo->CreationStatus = STATUS_ACCESS_DENIED;
}
else
{
// 程序銷燬
}
}
二、關鍵操作
2.1 連結器設定
上述程式碼編譯後,無法正確觸發 ProcessNotifyRoutine
回撥,需要為連結器增加引數:
/INTEGRITYCHECK
這一點需要著重注意。
2.2 PsSetCreateProcessNotifyRoutineEx 註冊回撥
函式原型:
NTSTATUS
PsSetCreateProcessNotifyRoutineEx (
_In_ PCREATE_PROCESS_NOTIFY_ROUTINE_EX NotifyRoutine,
_In_ BOOLEAN Remove
);
引數解釋:
第一個引數:回撥函式,當程序建立或者銷燬時會呼叫此函式,型別為 PCREATE_PROCESS_NOTIFY_ROUTINE_EX
第二個引數:是否移除,true表示移除,false表示註冊
其中PCREATE_PROCESS_NOTIFY_ROUTINE_EX
定義為:
typedef
VOID
(*PCREATE_PROCESS_NOTIFY_ROUTINE_EX) (
_Inout_ PEPROCESS Process,
_In_ HANDLE ProcessId,
_Inout_opt_ PPS_CREATE_NOTIFY_INFO CreateInfo
);
PEPROCESS
是核心態程序物件,HANDLE
是程序ID,PPS_CREATE_NOTIFY_INFO
是程序建立資訊,如果為NULL,表示程序銷燬,否則表示程序建立。
2.3 獲取程序資訊
如上的 PCREATE_PROCESS_NOTIFY_ROUTINE_EX
定義,我們可以透過回撥函式的 CreateInfo
引數獲取程序相關資訊。
PPS_CREATE_NOTIFY_INFO
定義如下:
typedef struct _PS_CREATE_NOTIFY_INFO {
_In_ SIZE_T Size;
union {
_In_ ULONG Flags;
struct {
_In_ ULONG FileOpenNameAvailable : 1;
_In_ ULONG Reserved : 31;
};
};
_In_ HANDLE ParentProcessId;
_In_ CLIENT_ID CreatingThreadId;
_Inout_ struct _FILE_OBJECT *FileObject;
_In_ PCUNICODE_STRING ImageFileName;
_In_opt_ PCUNICODE_STRING CommandLine;
_Inout_ NTSTATUS CreationStatus;
} PS_CREATE_NOTIFY_INFO, *PPS_CREATE_NOTIFY_INFO;
可以直接獲得:
ParentProcessId
:父程序IDCreatingThreadId
:建立程序的執行緒IDFileObject
:檔案物件,可以獲得檔案路徑ImageFileName
:程序映像檔名,也就是可執行檔案路徑CommandLine
:程序啟動命令列,如果為NULL,表示沒有命令列,否則為命令列字串
2.4 阻止程序建立
PPS_CREATE_NOTIFY_INFO
中有一個 CreationStatus
欄位,如果設定為 STATUS_ACCESS_DENIED
,則表示阻止程序建立。
三、參考資料
[1] Windows 核心不透明結構
[2] PsSetCreateProcessNotifyRoutineEx 函式 (ntddk.h)
[3] PCREATE_PROCESS_NOTIFY_ROUTINE_EX回撥函式 (ntddk.h)
[4] PS_CREATE_NOTIFY_INFO 結構 (ntddk.h)