您的位置:首頁 >財經 >

每日速讀!驅動開發:內核中進程與句柄互轉

2023-06-23 12:31:34 來源:博客園

在內核開發中,經常需要進行進程和句柄之間的互相轉換。進程通常由一個唯一的進程標識符(PID)來標識,而句柄是指對內核對象的引用。在Windows內核中,EProcess結構表示一個進程,而HANDLE是一個句柄。

為了實現進程與句柄之間的轉換,我們需要使用一些內核函數。對于進程PID和句柄的互相轉換,可以使用函數如OpenProcessGetProcessId。OpenProcess函數接受一個PID作為參數,并返回一個句柄。GetProcessId函數接受一個句柄作為參數,并返回該進程的PID。


(相關資料圖)

對于進程PID和EProcess結構的互相轉換,可以使用函數如PsGetProcessIdPsGetCurrentProcess。PsGetProcessId函數接受一個EProcess結構作為參數,并返回該進程的PID。PsGetCurrentProcess函數返回當前進程的EProcess結構。

最后,對于句柄和EProcess結構的互相轉換,可以使用函數如ObReferenceObjectByHandle和PsGetProcessId。ObReferenceObjectByHandle函數接受一個句柄和一個對象類型作為參數,并返回對該對象的引用。PsGetProcessId函數接受一個EProcess結構作為參數,并返回該進程的PID。

掌握這些內核函數的使用,可以方便地實現進程與句柄之間的互相轉換。在進行進程和線程的內核開發之前,了解這些轉換功能是非常重要的。

進程PID與進程HANDLE之間的互相轉換:進程PID轉化為HANDLE句柄,可通過ZwOpenProcess這個內核函數,傳入PID傳出進程HANDLE句柄,如果需要將HANDLE句柄轉化為PID則可通過ZwQueryInformationProcess這個內核函數來實現,具體轉換實現方法如下所示;

在內核開發中,經常需要進行進程PID和句柄HANDLE之間的互相轉換。將進程PID轉化為句柄HANDLE的方法是通過調用ZwOpenProcess內核函數,傳入PID作為參數,函數返回對應進程的句柄HANDLE。具體實現方法是,定義一個OBJECT_ATTRIBUTES結構體和CLIENT_ID結構體,將進程PID賦值給CLIENT_ID結構體的UniqueProcess字段,調用ZwOpenProcess函數打開進程,如果函數執行成功,將返回進程句柄HANDLE,否則返回NULL。

將句柄HANDLE轉化為進程PID的方法是通過調用ZwQueryInformationProcess內核函數,傳入進程句柄和信息類別作為參數,函數返回有關指定進程的信息,包括進程PID。具體實現方法是,定義一個PROCESS_BASIC_INFORMATION結構體和一個NTSTATUS變量,調用ZwQueryInformationProcess函數查詢進程基本信息,如果函數執行成功,將返回進程PID,否則返回0。

其中ZwQueryInformationProcess是一個未被導出的函數如需使用要通過MmGetSystemRoutineAddress動態獲取到,該函數的原型定義如下:

NTSTATUS ZwQueryInformationProcess(  HANDLE           ProcessHandle,  PROCESSINFOCLASS ProcessInformationClass,  PVOID            ProcessInformation,  ULONG            ProcessInformationLength,  PULONG           ReturnLength);

函數可以接受一個進程句柄ProcessHandle、一個PROCESSINFOCLASS枚舉類型的參數ProcessInformationClass、一個用于存儲返回信息的緩沖區ProcessInformation、緩沖區大小ProcessInformationLength和一個指向ULONG類型變量的指針ReturnLength作為參數。

在調用該函數時,ProcessInformationClass參數指定要獲取的進程信息的類型。例如,如果要獲取進程的基本信息,則需要將該參數設置為ProcessBasicInformation;如果要獲取進程的映像文件名,則需要將該參數設置為ProcessImageFileName。調用成功后,返回的信息存儲在ProcessInformation緩沖區中。

在調用該函數時,如果ProcessInformation緩沖區的大小小于需要返回的信息大小,則該函數將返回STATUS_INFO_LENGTH_MISMATCH錯誤代碼,并將所需信息的大小存儲在ReturnLength指針指向的ULONG類型變量中。

ZwQueryInformationProcess函數的返回值為NTSTATUS類型,表示函數執行的結果狀態。如果函數執行成功,則返回STATUS_SUCCESS,否則返回其他錯誤代碼。

掌握這些轉換方法可以方便地在內核開發中進行進程PID和句柄HANDLE之間的互相轉換。

#include // 定義函數指針typedef NTSTATUS(*PfnZwQueryInformationProcess)(__in HANDLE ProcessHandle,__in PROCESSINFOCLASS ProcessInformationClass,__out_bcount(ProcessInformationLength) PVOID ProcessInformation,__in ULONG ProcessInformationLength,__out_opt PULONG ReturnLength);PfnZwQueryInformationProcess ZwQueryInformationProcess;// 傳入PID傳出HANDLE句柄HANDLE PidToHandle(ULONG PID){HANDLE hProcessHandle;OBJECT_ATTRIBUTES obj;CLIENT_ID clientid;clientid.UniqueProcess = PID;clientid.UniqueThread = 0;// 屬性初始化InitializeObjectAttributes(&obj, 0, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 0, 0);NTSTATUS status = ZwOpenProcess(&hProcessHandle, PROCESS_ALL_ACCESS, &obj, &clientid);if (status == STATUS_SUCCESS){// DbgPrint("[*] 已打開 \n");ZwClose(&hProcessHandle);return hProcessHandle;}return 0;}// HANDLE句柄轉換為PIDULONG HandleToPid(HANDLE handle){PROCESS_BASIC_INFORMATION ProcessBasicInfor;// 初始化字符串,并獲取動態地址UNICODE_STRING UtrZwQueryInformationProcessName = RTL_CONSTANT_STRING(L"ZwQueryInformationProcess");ZwQueryInformationProcess = (PfnZwQueryInformationProcess)MmGetSystemRoutineAddress(&UtrZwQueryInformationProcessName);// 調用查詢ZwQueryInformationProcess(handle,ProcessBasicInformation,(PVOID)&ProcessBasicInfor,sizeof(ProcessBasicInfor),NULL);// 返回進程PIDreturn ProcessBasicInfor.UniqueProcessId;}VOID UnDriver(PDRIVER_OBJECT driver){DbgPrint("[-] 驅動卸載 \n");}NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath){DbgPrint("Hello LyShark \n");// 將PID轉換為HANDLEHANDLE ptr = PidToHandle(6932);DbgPrint("[*] PID  --> HANDLE = %p \n", ptr);// 句柄轉為PIDULONG pid = HandleToPid(ptr);DbgPrint("[*] HANDLE  --> PID = %d \n", pid);Driver->DriverUnload = UnDriver;return STATUS_SUCCESS;}

編譯并運行如上這段代碼片段,將把進程PID轉為HANDLE句柄,再通過句柄將其轉為PID,輸出效果圖如下所示;

進程PID轉換為EProcess結構:通過PsLookUpProcessByProcessId函數,該函數傳入一個PID則可獲取到該PID的EProcess結構體,具體轉換實現方法如下所示;

本段代碼展示了如何使用Windows內核API函數PsLookupProcessByProcessId將一個PID(Process ID)轉換為對應的EProcess結構體,EProcess是Windows內核中描述進程的數據結構之一。

代碼段中定義了一個名為PidToObject的函數,該函數的輸入參數是一個PID,輸出參數是對應的EProcess結構體。

在函數中,通過調用PsLookupProcessByProcessId函數來獲取對應PID的EProcess結構體,如果獲取成功,則調用ObDereferenceObject函數來減少EProcess對象的引用計數,并返回獲取到的EProcess指針;否則返回0。

DriverEntry函數中,調用了PidToObject函數將PID 6932轉換為對應的EProcess結構體,并使用DbgPrint函數輸出了轉換結果。最后設置了驅動程序卸載函數為UnDriver,當驅動程序被卸載時,UnDriver函數會被調用。

#include #include // 將Pid轉換為Object or EProcessPEPROCESS PidToObject(ULONG Pid){PEPROCESS pEprocess;NTSTATUS status = PsLookupProcessByProcessId((HANDLE)Pid, &pEprocess);if (status == STATUS_SUCCESS){ObDereferenceObject(pEprocess);return pEprocess;}return 0;}VOID UnDriver(PDRIVER_OBJECT driver){DbgPrint("[-] 驅動卸載 \n");}NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath){DbgPrint("Hello LyShark \n");// 將PID轉換為PEPROCESSPEPROCESS ptr = PidToObject(6932);DbgPrint("[*] PID  --> PEPROCESS = %p \n", ptr);Driver->DriverUnload = UnDriver;return STATUS_SUCCESS;}

編譯并運行如上這段代碼片段,將把進程PID轉為EProcess結構,輸出效果圖如下所示;

進程HANDLE與EPROCESS互相轉換:Handle轉換為EProcess結構可使用內核函數ObReferenceObjectByHandle實現,反過來EProcess轉換為Handle句柄可使用ObOpenObjectByPointer內核函數實現,具體轉換實現方法如下所示;

首先,將Handle轉換為EProcess結構體,可以使用ObReferenceObjectByHandle內核函數。該函數接受一個Handle參數,以及對應的對象類型(這里為EProcess),并返回對應對象的指針。此函數會對返回的對象增加引用計數,因此在使用完畢后,需要使用ObDereferenceObject將引用計數減少。

其次,將EProcess結構體轉換為Handle句柄,可以使用ObOpenObjectByPointer內核函數。該函數接受一個指向對象的指針(這里為EProcess結構體的指針),以及所需的訪問權限和對象類型,并返回對應的Handle句柄。此函數會將返回的句柄添加到當前進程的句柄表中,因此在使用完畢后,需要使用CloseHandle函數將句柄關閉,以避免資源泄漏。

綜上所述,我們可以通過這兩個內核函數實現HandleEProcess之間的相互轉換,轉換代碼如下所示;

#include #include // 傳入PID傳出HANDLE句柄HANDLE PidToHandle(ULONG PID){HANDLE hProcessHandle;OBJECT_ATTRIBUTES obj;CLIENT_ID clientid;clientid.UniqueProcess = PID;clientid.UniqueThread = 0;// 屬性初始化InitializeObjectAttributes(&obj, 0, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 0, 0);NTSTATUS status = ZwOpenProcess(&hProcessHandle, PROCESS_ALL_ACCESS, &obj, &clientid);if (status == STATUS_SUCCESS){// DbgPrint("[*] 已打開 \n");ZwClose(&hProcessHandle);return hProcessHandle;}return 0;}// 將Handle轉換為EProcess結構PEPROCESS HandleToEprocess(HANDLE handle){PEPROCESS pEprocess;NTSTATUS status = ObReferenceObjectByHandle(handle, GENERIC_ALL, *PsProcessType, KernelMode, &pEprocess, NULL);if (status == STATUS_SUCCESS){return pEprocess;}return 0;}// EProcess轉換為Handle句柄HANDLE EprocessToHandle(PEPROCESS eprocess){HANDLE hProcessHandle = (HANDLE)-1;NTSTATUS status = ObOpenObjectByPointer(eprocess,OBJ_KERNEL_HANDLE,0,0,*PsProcessType,KernelMode,&hProcessHandle);if (status == STATUS_SUCCESS){return hProcessHandle;}return 0;}VOID UnDriver(PDRIVER_OBJECT driver){DbgPrint("[-] 驅動卸載 \n");}NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath){DbgPrint("Hello LyShark \n");// 將Handle轉換為EProcess結構PEPROCESS eprocess = HandleToEprocess(PidToHandle(6932));DbgPrint("[*] HANDLE --> EProcess = %p \n", eprocess);// 將EProcess結構轉換為HandleHANDLE handle = EprocessToHandle(eprocess);DbgPrint("[*] EProcess --> HANDLE = %p \n", handle);Driver->DriverUnload = UnDriver;return STATUS_SUCCESS;}

編譯并運行如上這段代碼片段,將把進程HANDLEEProcess結構互轉,輸出效果圖如下所示;

關鍵詞: