在內核開發中,經常需要進行進程和句柄之間的互相轉換。進程通常由一個唯一的進程標識符(PID)來標識,而句柄是指對內核對象的引用。在Windows內核中,`EProcess`結構表示一個進程,而HANDLE是一個句柄。為了實現進程與句柄之間的轉換,我們需要使用一些內核函數。對於進程PID和句柄的互相轉... ...
在內核開發中,經常需要進行進程和句柄之間的互相轉換。進程通常由一個唯一的進程標識符(PID)來標識,而句柄是指對內核對象的引用。在Windows內核中,EProcess
結構表示一個進程,而HANDLE是一個句柄。
為了實現進程與句柄之間的轉換,我們需要使用一些內核函數。對於進程PID和句柄的互相轉換,可以使用函數如OpenProcess
和GetProcessId
。OpenProcess函數接受一個PID作為參數,並返回一個句柄。GetProcessId函數接受一個句柄作為參數,並返回該進程的PID。
對於進程PID和EProcess
結構的互相轉換,可以使用函數如PsGetProcessId
和PsGetCurrentProcess
。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 <ntifs.h>
// 定義函數指針
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句柄轉換為PID
ULONG 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);
// 返回進程PID
return ProcessBasicInfor.UniqueProcessId;
}
VOID UnDriver(PDRIVER_OBJECT driver)
{
DbgPrint("[-] 驅動卸載 \n");
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
DbgPrint("Hello LyShark \n");
// 將PID轉換為HANDLE
HANDLE ptr = PidToHandle(6932);
DbgPrint("[*] PID --> HANDLE = %p \n", ptr);
// 句柄轉為PID
ULONG 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 <ntifs.h>
#include <windef.h>
// 將Pid轉換為Object or EProcess
PEPROCESS 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轉換為PEPROCESS
PEPROCESS 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
函數將句柄關閉,以避免資源泄漏。
綜上所述,我們可以通過這兩個內核函數實現Handle
和EProcess
之間的相互轉換,轉換代碼如下所示;
#include <ntifs.h>
#include <windef.h>
// 傳入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結構轉換為Handle
HANDLE handle = EprocessToHandle(eprocess);
DbgPrint("[*] EProcess --> HANDLE = %p \n", handle);
Driver->DriverUnload = UnDriver;
return STATUS_SUCCESS;
}
編譯並運行如上這段代碼片段,將把進程HANDLE
與EProcess
結構互轉,輸出效果圖如下所示;
文章出處:https://www.cnblogs.com/LyShark/p/17173641.html
本博客所有文章除特別聲明外,均採用 BY-NC-SA 許可協議。轉載請註明出處!