Windows內核除了可以監聽進程,線程、dll還可以監聽特定的對象和注冊表。這里先講一下監聽對象。
監聽對象
內核提供了一種可以監聽對特定的對象類型的句柄進行打開或復制的機制。正式支持的對象類型有進程和線程,Windows10還支持一個桌面對象(桌面對象這個先不考慮)。
這個和前面的監聽進程線程以及模塊加載是有區別的。這個是相對於對象的句柄的,比如說一個進程的句柄,線程的句柄,別的進程通過關閉這個進程的句柄來關閉這個進程這種。是這個意思。
這里也有很多和前面相似的地方。
比如說,首先得注冊通知。
注冊對象通知
注冊對象通知的主要API:
NTSTATUS ObRegisterCallbacks(
POB_CALLBACK_REGISTRATION CallbackRegistration,
PVOID *RegistrationHandle
);
如果采用這個API,必須在鏈接是開啟/integritycheck

void ObUnRegisterCallbacks(
PVOID RegistrationHandle
);//關閉注冊的API
整體說明下這兩個API如何使用:
首先有一個公用的參數 RegistrationHandle,這個參數在注冊的API里面是一個輸出參數,然后在取消注冊里面是一個輸入參數,相當於這個參數會和注冊的對象進行一個綁定,通過注冊API會給它賦一個值,然后取消注冊API會通過它的值,來唯一標識一個對象進行取消注冊這樣子。
比較重要的是注冊API的第一個參數:CallbackRegistration。
typedef struct _OB_CALLBACK_REGISTRATION {
USHORT Version;
USHORT OperationRegistrationCount;
UNICODE_STRING Altitude;
PVOID RegistrationContext;
OB_OPERATION_REGISTRATION *OperationRegistration;
} OB_CALLBACK_REGISTRATION, *POB_CALLBACK_REGISTRATION;
這個結構體是必須在注冊前先初始化的。
_OB_CALLBACK_REGISTRATION
這個結構體比較重要,需要展開講講。
字段 | 含義 |
---|---|
Version | 必須為設置為OB_FLT_REGISTRATION_VERSION |
OperationRegistrationCount | 被注冊的數量,指定了OperationRegistration指向的結構體數量。 |
Altitude | 這個高度值,用來標榜被調用的順序,值越高在調用鏈中就越早。但是不能和之前的值有重復值,這個其實沒啥用,最主要的是防止重復了。這個值是一個無限精度的十進制數字,所以小數或者隨機數都可以,最主要的別重復了。一般會多寫點,比如說 123145,111111這種,就很大程度上可以規避重復。 |
RegistrationContext | 這個值由系統和驅動自動賦值,傳個NULL就行 |
OperationRegistration | 這個值比較重要且復雜,單獨解釋。 |
OperationRegistration
這個結構體用來具體標榜要通知的內容的信息:
typedef struct _OB_OPERATION_REGISTRATION {
POBJECT_TYPE *ObjectType;
OB_OPERATION Operations;
POB_PRE_OPERATION_CALLBACK PreOperation;
POB_POST_OPERATION_CALLBACK PostOperation;
} OB_OPERATION_REGISTRATION, *POB_OPERATION_REGISTRATION;
字段 | 內容 |
---|---|
ObjectType | 標記要通知的對象的類型:進程、線程、桌面。PsProcessType PsThreadType ExDesktopObjectType。 |
Operations | 標記要做的操作,打開創建還是復制。OB_OPERATION_HANDLE_CREATE OB_OPERATION_HANDLE_DUPLICATE |
PreOperation | 一個函數指針PobPreOperationCallback,在系統調用涉及到對象的時候之前就采用這個回調函數。 |
PostOperation | 一個函數指針PobPreOperationCallback,在系統調用涉及到對象的時候之后就采用這個回調函數。 |
POB_PRE_OPERATION_CALLBACK PobPreOperationCallback;
OB_PREOP_CALLBACK_STATUS PobPreOperationCallback(
PVOID RegistrationContext,
POB_PRE_OPERATION_INFORMATION OperationInformation
)
{...}
POB_POST_OPERATION_CALLBACK PobPostOperationCallback;
void PobPostOperationCallback(
PVOID RegistrationContext,
POB_POST_OPERATION_INFORMATION OperationInformation
)
{...}
這里面的RegistrationContext是上下文寄存器環境OperationInformation是記錄着一些相關的對象信息。
這個OperationInformation大同小異,比如說調用前的OperationInformation就是這個結構體:
typedef struct _OB_PRE_OPERATION_INFORMATION {
OB_OPERATION Operation;
union {
ULONG Flags;
struct {
ULONG KernelHandle : 1;
ULONG Reserved : 31;
};
};
PVOID Object;
POBJECT_TYPE ObjectType;
PVOID CallContext;
POB_PRE_OPERATION_PARAMETERS Parameters;
} OB_PRE_OPERATION_INFORMATION, *POB_PRE_OPERATION_INFORMATION;
字段 | 意義 |
---|---|
Operation | 操作類型 |
KernelHandle | 是否是內核對象 |
Object | 進程就是EPROCESS,線程就是PETHREAD |
ObjectType | 對象的類型,和前面一樣 |
CallContext | 驅動自動賦值,不是很重要,這里用不到 |
Parameters | 基於操作的附加信息 |
針對parameter又有擴展內容:
typedef union _OB_PRE_OPERATION_PARAMETERS {
OB_PRE_CREATE_HANDLE_INFORMATION CreateHandleInformation;
OB_PRE_DUPLICATE_HANDLE_INFORMATION DuplicateHandleInformation;
} OB_PRE_OPERATION_PARAMETERS, *POB_PRE_OPERATION_PARAMETERS;
然后這里的CreateHandleInformation我們用得上:
typedef struct _OB_PRE_CREATE_HANDLE_INFORMATION {
ACCESS_MASK DesiredAccess;
ACCESS_MASK OriginalDesiredAccess;
} OB_PRE_CREATE_HANDLE_INFORMATION, *POB_PRE_CREATE_HANDLE_INFORMATION;
DesiredAccess表示的是訪問掩碼,也就是獲得對進程操作的權限,我們只要在這里把關閉進程的權限給刪除了就好了。
實例代碼:
由於各種API啊,各種結構體啊,調用起來層次復雜,光這樣講肯定是少了很多東西,用一個實際場景來講會更好。
這里提供一個保護進程的思想,就是通過進程的PID來進行保護,刪除除掉別的進程打開保護進程的句柄時的關閉權限。就行了。
思路的話就是通過調用前,判斷是不是我們保護的進程,如果是就不讓關閉了,刪除掉PROCESS_TERMINATE權限。,其實比較簡單。
整個驅動的代碼我寫好打包上github了:
https://github.com/skrandy/ProtectYourProcess。
最終結果:
添加了保護后,再用任務管理器就無法關閉了。
小結