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

目录

  • 一丶简介
    • 二丶原理
      • 1.原理
      • 2.代码实现.

一丶简介

我们遇到的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
内核中通过进程PID获取进程的全部路径_第1张图片

2.使用RtlVolumeDeviceToDosName 得到盘符
内核中通过进程PID获取进程的全部路径_第2张图片

3.拼接路径为UNICODE_STRING类型
内核中通过进程PID获取进程的全部路径_第3张图片

4.为传入的ANSI_STRING 分配空间转换.得到ANSI_STRING路径.
内核中通过进程PID获取进程的全部路径_第4张图片

你可能感兴趣的:(内核中通过进程PID获取进程的全部路径)