内核中获取进程路径学习

NTSTATUS PsGetProcessPathByPid( IN ULONG Pid ,char* FilePath)
{
NTSTATUS       status;

char       path[256] = {0};
char       disk[10] = {0};
STRING        ansi_path;
STRING        ansi_disk;
UNICODE_STRING     uni_path;
UNICODE_STRING     uni_disk;
  
PEPROCESS       pEprocess;
PFILE_OBJECT      FileObject;
PVOID       Object;

status = PsLookupProcessByProcessId(Pid,&pEprocess);

if(!NT_SUCCESS(status))
{
   DbgPrint("EPROCESS Error");
   return STATUS_UNSUCCESSFUL;
} DbgPrint("EPROCESS 0x%0.8X",pEprocess);

if( !MmIsAddressValid( (PULONG)( (ULONG)pEprocess+0x138 ) ) )//EPROCESS+0x138 -> SectionObject

{   DbgPrint("SectionObject Error");
   return STATUS_UNSUCCESSFUL;
} Object = (PVOID)(*(PULONG)((ULONG)pEprocess+0x138));

if( !MmIsAddressValid( (PULONG)( (ULONG)Object+0x014 ) ) )//SectionObject+0x014 -> Segment
{
   DbgPrint("Segment Error");
   return STATUS_UNSUCCESSFUL;
} Object = (PVOID)(*(PULONG)( (ULONG)Object+0x014 ));
  
if( !MmIsAddressValid( (PULONG)((ULONG)Object+0x000) ) )//Segment+0x000 -> ControlAera
{
   DbgPrint("ControlAera Error");
   return STATUS_UNSUCCESSFUL;
} Object = (PVOID)(*(PULONG)( (ULONG)Object+0x000 ));
  
if( !MmIsAddressValid( (PULONG)( (ULONG)Object+0x024 ) ) )//ControlAera+0x024 -> FilePointer(FileObject)
{
   DbgPrint("FilePointer Error");
   return STATUS_UNSUCCESSFUL;
} Object = (PVOID)(*(PULONG)( (ULONG)Object+0x024 ));
  
FileObject = Object;
ObReferenceObjectByPointer((PVOID)FileObject,0,NULL,KernelMode);
RtlInitUnicodeString(&uni_path,FileObject->FileName.Buffer); //获取路径名
RtlVolumeDeviceToDosName(FileObject->DeviceObject,&uni_disk); //获取盘符名
ObDereferenceObject(FileObject);

RtlUnicodeStringToAnsiString(&ansi_path,&uni_path,TRUE);
RtlUnicodeStringToAnsiString(&ansi_disk,&uni_disk,TRUE);

strcat(path,&ansi_path.Buffer[0]);
strcat(disk,&ansi_disk.Buffer[0]);

RtlFreeAnsiString(&ansi_path);
RtlFreeAnsiString(&ansi_disk);
  
if( strlen(path)+strlen(disk) < 256 )
{
   strcat(FilePath,disk);
   strcat(FilePath,path);
}
else
{
   strcat(FilePath,disk);
   memcpy( FilePath,path,256-strlen(disk)-1 );
   *(FilePath + 256) = 0;
}
return STATUS_SUCCESS;
}

<think>我们正在处理一个关于Windows内核模式下获取进程路径的问题。用户需要方法或代码示例。在Windows内核编程中,获取进程的全路径(即映像文件的完整路径)是一个常见的需求。我们可以使用内核API来获取这些信息。根据Windows内核编程的常识,我们可以通过以下步骤实现:1.获取目标进程的EPROCESS结构。2.从EPROCESS结构中获取进程的PEB(进程环境块)地址。3.在PEB中,我们可以找到进程的映像文件路径。但是,在内核模式下直接访问用户空间的PEB可能不是最佳实践,因为PEB位于用户空间,且访问需要确保安全。更可靠的方法是使用内核函数如`ZwQueryInformationProcess`或`SeLocateProcessImageName`等。然而,需要注意的是,在最新的Windows版本中,某些方法可能已经改变,且直接访问PEB可能在某些情况下会导致问题(例如,进程正在退出时)。因此,我们通常使用内核提供的函数来获取这些信息。这里介绍两种常用方法:方法一:使用`ZwQueryInformationProcess`这是最标准的方法。我们可以使用`ZwQueryInformationProcess`函数并指定`ProcessImageFileName`信息类(但是注意,这个信息类返回的是一个`OBJECT_NAME_INFORMATION`结构,其中包含的是设备名称格式的路径,如`\Device\HarddiskVolume1\Windows\System32\notepad.exe`)。我们可以将其转换为DOS路径,但转换并不总是必要的,具体取决于需求。方法二:使用`SeLocateProcessImageName`这个函数可以返回一个指向UNICODE_STRING的指针,其中包含进程映像文件的完整路径(也是设备路径格式)。注意:这个函数未公开,需要动态获取。但在内核开发中,有时会使用未公开的函数,但这样会影响兼容性。考虑到稳定性和公开性,推荐使用`ZwQueryInformationProcess`。下面是一个使用`ZwQueryInformationProcess`的示例代码框架:```c#include<ntifs.h>#include<wdm.h>NTSTATUSGetProcessImagePath(PEPROCESSProcess,PUNICODE_STRING*ImagePath){NTSTATUSstatus=STATUS_SUCCESS;HANDLEprocessHandle=NULL;PAGED_CODE();//打开目标进程的句柄,注意:我们已经有EPROCESS,但需要获得一个HANDLE//使用ObOpenObjectByPointer打开进程句柄status=ObOpenObjectByPointer(Process,OBJ_KERNEL_HANDLE,NULL,PROCESS_QUERY_INFORMATION,*PsProcessType,KernelMode,&processHandle);if(!NT_SUCCESS(status)){returnstatus;}//第一次调用获取所需大小ULONGreturnLength=0;status=ZwQueryInformationProcess(processHandle,ProcessImageFileName,NULL,0,&returnLength);if(status!=STATUS_INFO_LENGTH_MISMATCH){//如果不是长度错误,则失败ZwClose(processHandle);returnstatus;}//分配内存以存储路径信息PUNICODE_STRINGimagePath=(PUNICODE_STRING)ExAllocatePoolWithTag(PagedPool,returnLength,'Tag1');if(imagePath==NULL){ZwClose(processHandle);returnSTATUS_INSUFFICIENT_RESOURCES;}//真正查询status=ZwQueryInformationProcess(processHandle,ProcessImageFileName,imagePath,returnLength,&returnLength);if(!NT_SUCCESS(status)){ExFreePoolWithTag(imagePath,'Tag1');ZwClose(processHandle);returnstatus;}//将结果返回,注意:调用者需要负责释放内存和关闭句柄*ImagePath=imagePath;ZwClose(processHandle);returnSTATUS_SUCCESS;}```注意:这个代码示例返回的设备路径(如`\Device\HarddiskVolume1\...`),如果需要转换为DOS路径(如`C:\...`),则需要额外的步骤,可以使用`IoQueryFileDosDeviceName`或`RtlVolumeDeviceToDosName`等函数进行转换,但这些函数可能未公开或需要谨慎使用。另外,我们也可以使用`ZwQueryInformationProcess`的另一个信息类`ProcessImageFileNameWin32`(如果可用),它可以直接返回Win32路径。但是,这个信息类可能只在某些版本中可用,不是标准的。考虑到用户的问题是在内核模式下获取路径,以上方法提供了基本思路。但实际应用中需注意内存管理、错误处理以及版本兼容性问题。最后,我们必须强调,内核编程涉及系统稳定性,务必谨慎处理资源释放(如句柄、内存)和避免在中断级不合适的上下文中调用函数(上述函数需要在PASSIVE_LEVEL下运行)。如果用户需要更具体的转换或其它方法,可以进一步讨论。根据用户要求,我们需要生成相关问题。</think> ### Windows内核模式获取进程路径的方法 在Windows内核模式下获取进程的全路径(即映像文件路径)可以通过以下方法实现: #### 方法一:使用`ZwQueryInformationProcess` 这是最可靠的标准方法: ```c #include <ntifs.h> #include <wdm.h> NTSTATUS GetProcessImagePath(PEPROCESS Process, PUNICODE_STRING ImagePath) { HANDLE hProcess; NTSTATUS status; ULONG returnLength = 0; PUNICODE_STRING pImageName = NULL; // 获取进程句柄 status = ObOpenObjectByPointer(Process, OBJ_KERNEL_HANDLE, NULL, PROCESS_QUERY_LIMITED_INFORMATION, *PsProcessType, KernelMode, &hProcess); if (!NT_SUCCESS(status)) return status; // 第一次调用获取所需缓冲区大小 ZwQueryInformationProcess(hProcess, ProcessImageFileName, NULL, 0, &returnLength); // 分配缓冲区 pImageName = ExAllocatePoolWithTag(PagedPool, returnLength, 'ImgP'); if (!pImageName) { ZwClose(hProcess); return STATUS_INSUFFICIENT_RESOURCES; } // 实际获取路径 status = ZwQueryInformationProcess(hProcess, ProcessImageFileName, pImageName, returnLength, &returnLength); if (NT_SUCCESS(status)) { // 复制结果到输出缓冲区 RtlCopyUnicodeString(ImagePath, pImageName); } ExFreePool(pImageName); ZwClose(hProcess); return status; } ``` - **关键点**: 1. 使用`ProcessImageFileName`信息类 2. 需要两次调用(先获取大小,再实际获取数据) 3. 返回的是**设备路径格式**(如 `\Device\HarddiskVolume1\Windows\System32\notepad.exe`) 4. 可通过`IoQueryFileDosDeviceName`转换为DOS路径(可选) #### 方法二:从PEB直接获取(适用于当前进程) ```c PPEB GetProcessPeb(PEPROCESS Process) { return (PPEB)PsGetProcessPeb(Process); } NTSTATUS GetCurrentProcessImagePath(PUNICODE_STRING ImagePath) { PEPROCESS pProcess = PsGetCurrentProcess(); PPEB pPeb = GetProcessPeb(pProcess); if (!pPeb || !pPeb->ProcessParameters) return STATUS_UNSUCCESSFUL; RtlCopyUnicodeString(ImagePath, &pPeb->ProcessParameters->ImagePathName); return STATUS_SUCCESS; } ``` - **限制**: - 仅适用于当前进程上下文 - 需要谨慎处理跨会话/保护进程 - 路径是用户空间数据,需进行内核地址验证 #### 重要注意事项: 1. **内存管理**:内核路径操作必须使用`ExAllocatePoolWithTag`分配内存 2. **安全边界**:某些进程(如受保护进程)可能无法访问[^1] 3. **IRQL要求**:必须在`PASSIVE_LEVEL`执行 4. **路径格式**:设备路径可能需要转换为DOS路径: ```c NTSTATUS ConvertToDosPath(PUNICODE_STRING DevicePath, PUNICODE_STRING DosPath) { return IoQueryFileDosDeviceName(DevicePath, DosPath); } ``` 5. **驱动签名**:此类操作需要签名内核驱动才能在64位系统加载[^2] > 实际使用示例:获取当前进程路径 > ```c > UNICODE_STRING ImagePath; > RtlInitEmptyUnicodeString(&ImagePath, NULL, 0); > GetProcessImagePath(PsGetCurrentProcess(), &ImagePath); > DbgPrint("Process path: %wZ\n", &ImagePath); > ExFreePool(ImagePath.Buffer); > ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值