怎样在windows内核中根据进程名获取执行程序的路径

Posted

tags:

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

参考技术A cmd>wmic>process

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内核中根据进程名获取执行程序的路径的主要内容,如果未能解决你的问题,请参考以下文章

Python 使用标准库根据进程名获取进程PID

qt怎么查看当前正在执行的代码

怎样查vnc端口,Linux下根据进程名怎样查端口

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

java在windows下如何实现获取进程ID

如何通过进程id枚举到所有的窗口