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