一丶簡介
我們遇到的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路徑.