内核中通过进程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路径.
