Windows內核開發-10-監聽對象
- 2021 年 10 月 22 日
- 筆記
- Windows內核安全與驅動開發
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了:
//github.com/skrandy/ProtectYourProcess。
最終結果:
添加了保護後,再用任務管理器就無法關閉了。
小結