内核中通过进程PID获取进程的全部路径

一丶简介

我们遇到的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路径.

原文地址:https://www.cnblogs.com/iBinary/p/11371168.html