Windows核心驅動-程序回撥

轻聆月下發表於2024-11-01

一、核心程式碼

一共三部分:

  1. 定義回撥函式
  2. 註冊回撥
  3. 移除回撥
#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:父程序ID
  • CreatingThreadId:建立程序的執行緒ID
  • FileObject:檔案物件,可以獲得檔案路徑
  • 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)

相關文章