您的位置:首頁(yè) >財(cái)經(jīng) >

每日速讀!驅(qū)動(dòng)開發(fā):內(nèi)核中進(jìn)程與句柄互轉(zhuǎn)

2023-06-23 12:31:34 來(lái)源:博客園

在內(nèi)核開發(fā)中,經(jīng)常需要進(jìn)行進(jìn)程和句柄之間的互相轉(zhuǎn)換。進(jìn)程通常由一個(gè)唯一的進(jìn)程標(biāo)識(shí)符(PID)來(lái)標(biāo)識(shí),而句柄是指對(duì)內(nèi)核對(duì)象的引用。在Windows內(nèi)核中,EProcess結(jié)構(gòu)表示一個(gè)進(jìn)程,而HANDLE是一個(gè)句柄。

為了實(shí)現(xiàn)進(jìn)程與句柄之間的轉(zhuǎn)換,我們需要使用一些內(nèi)核函數(shù)。對(duì)于進(jìn)程PID和句柄的互相轉(zhuǎn)換,可以使用函數(shù)如OpenProcessGetProcessId。OpenProcess函數(shù)接受一個(gè)PID作為參數(shù),并返回一個(gè)句柄。GetProcessId函數(shù)接受一個(gè)句柄作為參數(shù),并返回該進(jìn)程的PID。


(相關(guān)資料圖)

對(duì)于進(jìn)程PID和EProcess結(jié)構(gòu)的互相轉(zhuǎn)換,可以使用函數(shù)如PsGetProcessIdPsGetCurrentProcess。PsGetProcessId函數(shù)接受一個(gè)EProcess結(jié)構(gòu)作為參數(shù),并返回該進(jìn)程的PID。PsGetCurrentProcess函數(shù)返回當(dāng)前進(jìn)程的EProcess結(jié)構(gòu)。

最后,對(duì)于句柄和EProcess結(jié)構(gòu)的互相轉(zhuǎn)換,可以使用函數(shù)如ObReferenceObjectByHandle和PsGetProcessId。ObReferenceObjectByHandle函數(shù)接受一個(gè)句柄和一個(gè)對(duì)象類型作為參數(shù),并返回對(duì)該對(duì)象的引用。PsGetProcessId函數(shù)接受一個(gè)EProcess結(jié)構(gòu)作為參數(shù),并返回該進(jìn)程的PID。

掌握這些內(nèi)核函數(shù)的使用,可以方便地實(shí)現(xiàn)進(jìn)程與句柄之間的互相轉(zhuǎn)換。在進(jìn)行進(jìn)程和線程的內(nèi)核開發(fā)之前,了解這些轉(zhuǎn)換功能是非常重要的。

進(jìn)程PID與進(jìn)程HANDLE之間的互相轉(zhuǎn)換:進(jìn)程PID轉(zhuǎn)化為HANDLE句柄,可通過(guò)ZwOpenProcess這個(gè)內(nèi)核函數(shù),傳入PID傳出進(jìn)程HANDLE句柄,如果需要將HANDLE句柄轉(zhuǎn)化為PID則可通過(guò)ZwQueryInformationProcess這個(gè)內(nèi)核函數(shù)來(lái)實(shí)現(xiàn),具體轉(zhuǎn)換實(shí)現(xiàn)方法如下所示;

在內(nèi)核開發(fā)中,經(jīng)常需要進(jìn)行進(jìn)程PID和句柄HANDLE之間的互相轉(zhuǎn)換。將進(jìn)程PID轉(zhuǎn)化為句柄HANDLE的方法是通過(guò)調(diào)用ZwOpenProcess內(nèi)核函數(shù),傳入PID作為參數(shù),函數(shù)返回對(duì)應(yīng)進(jìn)程的句柄HANDLE。具體實(shí)現(xiàn)方法是,定義一個(gè)OBJECT_ATTRIBUTES結(jié)構(gòu)體和CLIENT_ID結(jié)構(gòu)體,將進(jìn)程PID賦值給CLIENT_ID結(jié)構(gòu)體的UniqueProcess字段,調(diào)用ZwOpenProcess函數(shù)打開進(jìn)程,如果函數(shù)執(zhí)行成功,將返回進(jìn)程句柄HANDLE,否則返回NULL。

將句柄HANDLE轉(zhuǎn)化為進(jìn)程PID的方法是通過(guò)調(diào)用ZwQueryInformationProcess內(nèi)核函數(shù),傳入進(jìn)程句柄和信息類別作為參數(shù),函數(shù)返回有關(guān)指定進(jìn)程的信息,包括進(jìn)程PID。具體實(shí)現(xiàn)方法是,定義一個(gè)PROCESS_BASIC_INFORMATION結(jié)構(gòu)體和一個(gè)NTSTATUS變量,調(diào)用ZwQueryInformationProcess函數(shù)查詢進(jìn)程基本信息,如果函數(shù)執(zhí)行成功,將返回進(jìn)程PID,否則返回0。

其中ZwQueryInformationProcess是一個(gè)未被導(dǎo)出的函數(shù)如需使用要通過(guò)MmGetSystemRoutineAddress動(dòng)態(tài)獲取到,該函數(shù)的原型定義如下:

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

函數(shù)可以接受一個(gè)進(jìn)程句柄ProcessHandle、一個(gè)PROCESSINFOCLASS枚舉類型的參數(shù)ProcessInformationClass、一個(gè)用于存儲(chǔ)返回信息的緩沖區(qū)ProcessInformation、緩沖區(qū)大小ProcessInformationLength和一個(gè)指向ULONG類型變量的指針ReturnLength作為參數(shù)。

在調(diào)用該函數(shù)時(shí),ProcessInformationClass參數(shù)指定要獲取的進(jìn)程信息的類型。例如,如果要獲取進(jìn)程的基本信息,則需要將該參數(shù)設(shè)置為ProcessBasicInformation;如果要獲取進(jìn)程的映像文件名,則需要將該參數(shù)設(shè)置為ProcessImageFileName。調(diào)用成功后,返回的信息存儲(chǔ)在ProcessInformation緩沖區(qū)中。

在調(diào)用該函數(shù)時(shí),如果ProcessInformation緩沖區(qū)的大小小于需要返回的信息大小,則該函數(shù)將返回STATUS_INFO_LENGTH_MISMATCH錯(cuò)誤代碼,并將所需信息的大小存儲(chǔ)在ReturnLength指針指向的ULONG類型變量中。

ZwQueryInformationProcess函數(shù)的返回值為NTSTATUS類型,表示函數(shù)執(zhí)行的結(jié)果狀態(tài)。如果函數(shù)執(zhí)行成功,則返回STATUS_SUCCESS,否則返回其他錯(cuò)誤代碼。

掌握這些轉(zhuǎn)換方法可以方便地在內(nèi)核開發(fā)中進(jìn)行進(jìn)程PID和句柄HANDLE之間的互相轉(zhuǎn)換。

#include // 定義函數(shù)指針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句柄轉(zhuǎn)換為PIDULONG HandleToPid(HANDLE handle){PROCESS_BASIC_INFORMATION ProcessBasicInfor;// 初始化字符串,并獲取動(dòng)態(tài)地址UNICODE_STRING UtrZwQueryInformationProcessName = RTL_CONSTANT_STRING(L"ZwQueryInformationProcess");ZwQueryInformationProcess = (PfnZwQueryInformationProcess)MmGetSystemRoutineAddress(&UtrZwQueryInformationProcessName);// 調(diào)用查詢ZwQueryInformationProcess(handle,ProcessBasicInformation,(PVOID)&ProcessBasicInfor,sizeof(ProcessBasicInfor),NULL);// 返回進(jìn)程PIDreturn ProcessBasicInfor.UniqueProcessId;}VOID UnDriver(PDRIVER_OBJECT driver){DbgPrint("[-] 驅(qū)動(dòng)卸載 \n");}NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath){DbgPrint("Hello LyShark \n");// 將PID轉(zhuǎn)換為HANDLEHANDLE ptr = PidToHandle(6932);DbgPrint("[*] PID  --> HANDLE = %p \n", ptr);// 句柄轉(zhuǎn)為PIDULONG pid = HandleToPid(ptr);DbgPrint("[*] HANDLE  --> PID = %d \n", pid);Driver->DriverUnload = UnDriver;return STATUS_SUCCESS;}

編譯并運(yùn)行如上這段代碼片段,將把進(jìn)程PID轉(zhuǎn)為HANDLE句柄,再通過(guò)句柄將其轉(zhuǎn)為PID,輸出效果圖如下所示;

進(jìn)程PID轉(zhuǎn)換為EProcess結(jié)構(gòu):通過(guò)PsLookUpProcessByProcessId函數(shù),該函數(shù)傳入一個(gè)PID則可獲取到該P(yáng)ID的EProcess結(jié)構(gòu)體,具體轉(zhuǎn)換實(shí)現(xiàn)方法如下所示;

本段代碼展示了如何使用Windows內(nèi)核API函數(shù)PsLookupProcessByProcessId將一個(gè)PID(Process ID)轉(zhuǎn)換為對(duì)應(yīng)的EProcess結(jié)構(gòu)體,EProcess是Windows內(nèi)核中描述進(jìn)程的數(shù)據(jù)結(jié)構(gòu)之一。

代碼段中定義了一個(gè)名為PidToObject的函數(shù),該函數(shù)的輸入?yún)?shù)是一個(gè)PID,輸出參數(shù)是對(duì)應(yīng)的EProcess結(jié)構(gòu)體。

在函數(shù)中,通過(guò)調(diào)用PsLookupProcessByProcessId函數(shù)來(lái)獲取對(duì)應(yīng)PID的EProcess結(jié)構(gòu)體,如果獲取成功,則調(diào)用ObDereferenceObject函數(shù)來(lái)減少EProcess對(duì)象的引用計(jì)數(shù),并返回獲取到的EProcess指針;否則返回0。

DriverEntry函數(shù)中,調(diào)用了PidToObject函數(shù)將PID 6932轉(zhuǎn)換為對(duì)應(yīng)的EProcess結(jié)構(gòu)體,并使用DbgPrint函數(shù)輸出了轉(zhuǎn)換結(jié)果。最后設(shè)置了驅(qū)動(dòng)程序卸載函數(shù)為UnDriver,當(dāng)驅(qū)動(dòng)程序被卸載時(shí),UnDriver函數(shù)會(huì)被調(diào)用。

#include #include // 將Pid轉(zhuǎn)換為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("[-] 驅(qū)動(dòng)卸載 \n");}NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath){DbgPrint("Hello LyShark \n");// 將PID轉(zhuǎn)換為PEPROCESSPEPROCESS ptr = PidToObject(6932);DbgPrint("[*] PID  --> PEPROCESS = %p \n", ptr);Driver->DriverUnload = UnDriver;return STATUS_SUCCESS;}

編譯并運(yùn)行如上這段代碼片段,將把進(jìn)程PID轉(zhuǎn)為EProcess結(jié)構(gòu),輸出效果圖如下所示;

進(jìn)程HANDLE與EPROCESS互相轉(zhuǎn)換:Handle轉(zhuǎn)換為EProcess結(jié)構(gòu)可使用內(nèi)核函數(shù)ObReferenceObjectByHandle實(shí)現(xiàn),反過(guò)來(lái)EProcess轉(zhuǎn)換為Handle句柄可使用ObOpenObjectByPointer內(nèi)核函數(shù)實(shí)現(xiàn),具體轉(zhuǎn)換實(shí)現(xiàn)方法如下所示;

首先,將Handle轉(zhuǎn)換為EProcess結(jié)構(gòu)體,可以使用ObReferenceObjectByHandle內(nèi)核函數(shù)。該函數(shù)接受一個(gè)Handle參數(shù),以及對(duì)應(yīng)的對(duì)象類型(這里為EProcess),并返回對(duì)應(yīng)對(duì)象的指針。此函數(shù)會(huì)對(duì)返回的對(duì)象增加引用計(jì)數(shù),因此在使用完畢后,需要使用ObDereferenceObject將引用計(jì)數(shù)減少。

其次,將EProcess結(jié)構(gòu)體轉(zhuǎn)換為Handle句柄,可以使用ObOpenObjectByPointer內(nèi)核函數(shù)。該函數(shù)接受一個(gè)指向?qū)ο蟮闹羔槪ㄟ@里為EProcess結(jié)構(gòu)體的指針),以及所需的訪問(wèn)權(quán)限和對(duì)象類型,并返回對(duì)應(yīng)的Handle句柄。此函數(shù)會(huì)將返回的句柄添加到當(dāng)前進(jìn)程的句柄表中,因此在使用完畢后,需要使用CloseHandle函數(shù)將句柄關(guān)閉,以避免資源泄漏。

綜上所述,我們可以通過(guò)這兩個(gè)內(nèi)核函數(shù)實(shí)現(xiàn)HandleEProcess之間的相互轉(zhuǎn)換,轉(zhuǎn)換代碼如下所示;

#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轉(zhuǎn)換為EProcess結(jié)構(gòu)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轉(zhuǎn)換為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("[-] 驅(qū)動(dòng)卸載 \n");}NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath){DbgPrint("Hello LyShark \n");// 將Handle轉(zhuǎn)換為EProcess結(jié)構(gòu)PEPROCESS eprocess = HandleToEprocess(PidToHandle(6932));DbgPrint("[*] HANDLE --> EProcess = %p \n", eprocess);// 將EProcess結(jié)構(gòu)轉(zhuǎn)換為HandleHANDLE handle = EprocessToHandle(eprocess);DbgPrint("[*] EProcess --> HANDLE = %p \n", handle);Driver->DriverUnload = UnDriver;return STATUS_SUCCESS;}

編譯并運(yùn)行如上這段代碼片段,將把進(jìn)程HANDLEEProcess結(jié)構(gòu)互轉(zhuǎn),輸出效果圖如下所示;

關(guān)鍵詞: