內核中通過進程PID獲取進程的全部路徑
- 2019 年 10 月 8 日
- 筆記
目錄
一丶簡介
我們遇到的Dos路徑.如果想轉化為NT路徑(也就是 C:xxxx)類似的格式 需要自己實現. 具體原理如下:
二丶原理
1.原理
1.使用** ZwOpenProcess ** 通過進程PID獲取HANDLE 2.使用** ZwQueryInformationProcess ** 查詢Handle,使用27號(ProcessFileNmae)得到NT路徑. 3.使用** ZwOpenFile 打開路徑得到Handle 4.使用 ObReferenceObjectByHandle ** 獲得 內核對象(FileObject) 5.從FileObject的成員FileName得到其路徑 6.使用 RtlVolumeDeviceToDosName 將FileObject設備對象傳入.獲得Dos路徑.也就是盤符 7.拼接路徑進行傳出
2.程式碼實現.
typedef NTSTATUS(*PfnZwQueryInformationProcess) ( __in HANDLE ProcessHandle, __in PROCESSINFOCLASS ProcessInformationClass, __out_bcount(ProcessInformationLength) PVOID ProcessInformation, __in ULONG ProcessInformationLength, __out_opt PULONG ReturnLength ); PfnZwQueryInformationProcess ZwQueryInformationProcess; //初始化未公開的導出函數 NTSTATUS InitGloableFunction() { UNICODE_STRING UtrZwQueryInformationProcessName = RTL_CONSTANT_STRING(L"ZwQueryInformationProcess"); ZwQueryInformationProcess = (PfnZwQueryInformationProcess)MmGetSystemRoutineAddress(&UtrZwQueryInformationProcessName); return STATUS_SUCCESS; } NTSTATUS GetDosPathByProcessId(IN ULONG pid,OUT PANSI_STRING pAnsiNtPath) { /* 1.根據PID獲取進程句柄 2.使用ZwQueryInformationProcess 傳入HANDLE 使用27號功能獲取路徑 */ HANDLE hProcess = 0; CLIENT_ID cid; OBJECT_ATTRIBUTES obj; NTSTATUS ntStatus; ULONG RetLength = 0; PVOID pBuffer = NULL; HANDLE hFile; IO_STATUS_BLOCK iostu; PVOID FileObject = NULL; PFILE_OBJECT pMyFileObject = NULL; UNICODE_STRING DosName; UNICODE_STRING FunllPath; if (ZwQueryInformationProcess == NULL) return STATUS_UNSUCCESSFUL; cid.UniqueProcess =(HANDLE)pid; cid.UniqueThread = 0; InitializeObjectAttributes(&obj, 0, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 0, 0); ntStatus = ZwOpenProcess(&hProcess, PROCESS_ALL_ACCESS, &obj, &cid); if (!NT_SUCCESS(ntStatus)) return STATUS_UNSUCCESSFUL; //使用27 號功能遍歷 ntStatus = ZwQueryInformationProcess(hProcess, ProcessImageFileName, NULL, 0, &RetLength); if (STATUS_INFO_LENGTH_MISMATCH != ntStatus) return STATUS_UNSUCCESSFUL; //申請記憶體繼續獲取. pBuffer = ExAllocatePoolWithTag(PagedPool, RetLength, 'niBI'); if (NULL == pBuffer) return STATUS_UNSUCCESSFUL; //重新調用獲取. ntStatus = ZwQueryInformationProcess(hProcess, ProcessImageFileName, pBuffer, RetLength, &RetLength); if (!NT_SUCCESS(ntStatus)) { if (NULL != pBuffer) { ExFreePoolWithTag(pBuffer, 'niBI'); } return STATUS_UNSUCCESSFUL; } //開始轉化路徑 InitializeObjectAttributes(&obj, pBuffer, OBJ_KERNEL_HANDLE, 0, 0); ntStatus = ZwOpenFile( &hFile, GENERIC_READ, &obj, &iostu, FILE_SHARE_READ| FILE_SHARE_WRITE , 0); if (!NT_SUCCESS(ntStatus)) { if (NULL != pBuffer) { ExFreePoolWithTag(pBuffer, 'niBI'); } ZwClose(hFile); return STATUS_UNSUCCESSFUL; } //獲得文件對象 ntStatus = ObReferenceObjectByHandle( hFile, GENERIC_ALL, *IoFileObjectType, KernelMode, &FileObject, NULL); if (!NT_SUCCESS(ntStatus)) { if (NULL != pBuffer) { ExFreePoolWithTag(pBuffer, 'niBI'); } ntStatus = ObDereferenceObject(FileObject); ZwClose(hFile); return STATUS_UNSUCCESSFUL; } pMyFileObject = (PFILE_OBJECT)FileObject; if (NULL == pMyFileObject) { if (NULL != pBuffer) { ExFreePoolWithTag(pBuffer, 'niBI'); } ntStatus = ObDereferenceObject(FileObject); ZwClose(hFile); return STATUS_UNSUCCESSFUL; } //通過 RtlVolumeDeviceToDosName 獲取Dos路徑 也即是C: D: 等盤符 RtlVolumeDeviceToDosName(pMyFileObject->DeviceObject,&DosName); //獲得路徑直接直接拼接即可. FunllPath.MaximumLength = pMyFileObject->FileName.MaximumLength + DosName.MaximumLength; FunllPath.Length = pMyFileObject->FileName.Length + DosName.Length; FunllPath.Buffer = ExAllocatePoolWithTag(NonPagedPool, FunllPath.MaximumLength, 0); //拼接路徑 RtlCopyUnicodeString(&FunllPath, &DosName);//得到C: RtlAppendUnicodeStringToString(&FunllPath, &pMyFileObject->FileName);//得到C:\xxx路徑,轉為Asii RtlUnicodeStringToAnsiString(pAnsiNtPath, &FunllPath,TRUE); //RtlFreeAnsiString 要釋放空間. ExFreePool(FunllPath.Buffer); //因為傳出自動為其分配了記憶體所以這個進行誰放 if (NULL != pBuffer) { ExFreePoolWithTag(pBuffer, 'niBI'); } ntStatus = ObDereferenceObject(FileObject); ZwClose(hFile); return STATUS_SUCCESS; } NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pRegPath) { ANSI_STRING AnsiNtPath; pDriverObj->DriverUnload = DriverUnLoad; InitGloableFunction(); KdBreakPoint(); GetDosPathByProcessId(3356,&AnsiNtPath); return STATUS_SUCCESS; }
以下為調試的時候的程式碼截圖. 1.得到FileName
2.使用RtlVolumeDeviceToDosName 得到盤符
3.拼接路徑為UNICODE_STRING類型
4.為傳入的ANSI_STRING 分配空間轉換.得到ANSI_STRING路徑.