windows 内核下获取进程路径

Posted priarienew

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了windows 内核下获取进程路径相关的知识,希望对你有一定的参考价值。

windows 内核下获取进程路径 

思路:
1):在EPROCESS结构中获取。
此时要用到一个导出函数:PsGetProcessImageFileName,申明如下:

NTSYSAPI
UCHAR *
    PsGetProcessImageFileName(
    __in PEPROCESS Process
    );

此函数获取的是一个简单的进程名,并不是绝对路径。

2):ZwQueryInformationProcess。

要想获取进程的绝对路径,可用一个未公开的函数:ZwQueryInformationProcess。MSDN上说win8以后此函数不支持了,但笔者在win7,win8 的x86,x64都试过了,都可以正常使用。笔者一般使用的时候用MmGetSystenRoutineAddress来找此函数的地址,找到后查找ProcessImageFileName(27号功能)信息,就可以得到UNICODE_STRING 类型的绝对进程路径,但此绝对路径并不是我我们在应用层看到的类似"C:windowsabc.exe"这样的路径,而是这样的表示方法"Deviceharddiskvolume1windowsabc.exe".

3):从FILE_OBJECT中获取

如果得到FILE_OBJECT的话可以从FILE_OBJECT中获取。

typedef struct _FILE_OBJECT {
  CSHORT                            Type;
  CSHORT                            Size;
  PDEVICE_OBJECT                    DeviceObject;
  PVPB                              Vpb;
  PVOID                             FsContext;
  PVOID                             FsContext2;
  PSECTION_OBJECT_POINTERS          SectionObjectPointer;
  PVOID                             PrivateCacheMap;
  NTSTATUS                          FinalStatus;
  struct _FILE_OBJECT  *RelatedFileObject;
  BOOLEAN                           LockOperation;
  BOOLEAN                           DeletePending;
  BOOLEAN                           ReadAccess;
  BOOLEAN                           WriteAccess;
  BOOLEAN                           DeleteAccess;
  BOOLEAN                           SharedRead;
  BOOLEAN                           SharedWrite;
  BOOLEAN                           SharedDelete;
  ULONG                             Flags;
  UNICODE_STRING                    FileName;
  LARGE_INTEGER                     CurrentByteOffset;
  __volatile ULONG                  Waiters;
  __volatile ULONG                  Busy;
  PVOID                             LastLock;
  KEVENT                            Lock;
  KEVENT                            Event;
  __volatile PIO_COMPLETION_CONTEXT CompletionContext;
  KSPIN_LOCK                        IrpListLock;
  LIST_ENTRY                        IrpList;
  __volatile PVOID                  FileObjectExtension;
} FILE_OBJECT, *PFILE_OBJECT;
FILE_OBJECT中两个重要的成员:FileName中含有除驱动器外的路径,比如是这样的"WINDOWSsystem32 otepad.exe"
此时再用另外一个函数IoVolumeDeviceToDosName,就可以将传入的DeviceObject转化为驱动器路径。
NTSTATUS IoVolumeDeviceToDosName( _In_  PVOID      VolumeDeviceObject, _Out_ PUNICODE_STRING DosName );
将DosName和FileName拼接起来就可以得到绝对路径"C:|windowssystem32 otepad.exe".
最后用完后记得要把DosName的Buffer空间释放掉。
MSDN如是说:

IoVolumeDeviceToDosName allocates the string buffer pointed to by the Buffer member of the UNICODE_STRING structure that the DosName parameter points to. After this buffer is no longer required, a caller of this routine should call the ExFreePool routine to free the buffer.

Starting with Windows Vista, you must ensure that APCs are not disabled before calling this routine. The KeAreAllApcsDisabled routine can be used to verify that APCs are not disabled

 

下面说几个常见的类型转换函数:

 ObReferenceObjectByHandle

此函数可以将句柄转化成内核对应的结构,例如:

进程句柄(HANDLE)------>进程活动链指针(PEPROCESS)

文件句柄(HANDLE)------>文件对象指针(PFILE_OBJECT)

懒的说了,还是看图吧,一图胜千言:

技术分享图片

PsGetProcessId
根据EPROCESS指针获取进程ID

最后贴一段练习的代码片段:

VOID GetProcPath(
	IN PRECORD_LIST pRecord,
	IN PHANDLE pHandle
	)
{
	NTSTATUS status = STATUS_SUCCESS;
	PUNICODE_STRING pUniImage = NULL;
	ULONG ulImageLen;

	UNICODE_STRING uniFunName = RTL_CONSTANT_STRING(L"ZwQueryInformationProcess");
	if (NULL == ZwQueryInformationProcess)
	{
		__try
		{
			ZwQueryInformationProcess = (PFUN_ZwQueryInformationProcess)MmGetSystemRoutineAddress(&uniFunName);
		}
		__except (EXCEPTION_EXECUTE_HANDLER)
		{
			KdPrint(("exception occured.
"));
		}
		
		if (NULL == ZwQueryInformationProcess)
		{
			KdPrint(("MmGetSystemRoutineAddress failed .
"));
			return;
		}
	}

	status = ZwQueryInformationProcess(*pHandle, ProcessImageFileName, pUniImage, 0, &ulImageLen);
	if (STATUS_INFO_LENGTH_MISMATCH != status)
	{
		KdPrint(("ZwQueryInformationProcess error code:(%x).
", status));
		return;
	}
	pUniImage = ExAllocatePoolWithTag(NonPagedPool, ulImageLen, MEMTAG);
	if (NULL == pUniImage)
	{
		KdPrint((" no enough resources .
"));
		return;
	}
	status = ZwQueryInformationProcess(*pHandle, ProcessImageFileName, pUniImage, ulImageLen, &ulImageLen);
	if (!NT_SUCCESS(status))
	{
		KdPrint(("ZwQueryInformationProcess error code:(%x).
", status));
		ExFreePool(pUniImage);
		return;
	}
	KdPrint(("ParentProcPath:(%wZ).
", pUniImage));
	ExFreePool(pUniImage);
}



NTSTATUS GetProcessIdByHandle(
	IN const PHANDLE pHandle,
	IN PULONG pPid)
{
	NTSTATUS status = STATUS_SUCCESS;
	PEPROCESS pEprocess = NULL;

	status = ObReferenceObjectByHandle(*pHandle, 0, *PsProcessType, KernelMode, &pEprocess, NULL);
	if (!NT_SUCCESS(status))
	{
		KdPrint((" error code:(%08x) 
", status));
		return status;
	}

	*pPid = (ULONG)PsGetProcessId(pEprocess);
	ObDereferenceObject(pEprocess);

	return status;
}

 


















以上是关于windows 内核下获取进程路径的主要内容,如果未能解决你的问题,请参考以下文章

内核中根据进程Pid获取Dos路径.

linux内核获取当前进程路径分析

LINUX PID 1和SYSTEMD PID 0 是内核的一部分,主要用于内进换页,内核初始化的最后一步就是启动 init 进程。这个进程是系统的第一个进程,PID 为 1,又叫超级进程(代码片段

windows内核代码之进程操作

windows-根据进程PID 获取进程路径

Win7 下DELPHI如何通过进程名获取路径