kenhuang 发表于 2017-6-1 13:33:02

NT5/NT6上的获取进程全路径

前面说过使用一大堆函数获取全路径


PID->eprocess->KeStackAttachProcess->ZwQueryInformationProcess->ProcessImageFileName->ZwCreateFile

->ObReferenceObjectByHandle->RtlVolumeDeviceToDosName
->ZwQueryInformationFile


code:

NTKERNELAPI NTSTATUS
PsLookupProcessByProcessId(
        IN HANDLE ProcessId,
        OUT PEPROCESS *Process
);


/*NTSTATUS
IoQueryFileDosDeviceName(
    IN PFILE_OBJECT FileObject,
    OUT POBJECT_NAME_INFORMATION *ObjectNameInformation
); */


NTSTATUS
NTAPI
ZwQueryInformationProcess(
                                                  __in HANDLE ProcessHandle,
                                                  __in PROCESSINFOCLASS ProcessInformationClass,
                                                  __out_bcount(ProcessInformationLength) PVOID ProcessInformation,
                                                  __in ULONG ProcessInformationLength,
                                                  __out_opt PULONG ReturnLength
    );



NTSTATUSGetProcessFullNameByPid(HANDLE nPid, PUNICODE_STRINGFullPath)
{

    HANDLE               hFile      = NULL;
    ULONG                nNeedSize        = 0;
    NTSTATUS             nStatus    = STATUS_SUCCESS;
    NTSTATUS             nDeviceStatus = STATUS_DEVICE_DOES_NOT_EXIST;
    PEPROCESS            Process    = NULL;
    KAPC_STATE         ApcState   = {0};                       
    PVOID                lpBuffer   = NULL;
    OBJECT_ATTRIBUTES       ObjectAttributes = {0};
    IO_STATUS_BLOCK      IoStatus   = {0};
    PFILE_OBJECT         FileObject = NULL;
    PFILE_NAME_INFORMATION FileName = NULL;   
    WCHAR                FileBuffer = {0};
    DECLARE_UNICODE_STRING_SIZE(ProcessPath,MAX_PATH);
    DECLARE_UNICODE_STRING_SIZE(DosDeviceName,MAX_PATH);
   
    PAGED_CODE();

    nStatus = PsLookupProcessByProcessId(nPid, &Process);
    if(NT_ERROR(nStatus))
    {
      KdPrint(("%s error PsLookupProcessByProcessId.\n",__FUNCTION__));
      return nStatus;
    }



    __try
    {

      KeStackAttachProcess(Process, &ApcState);
      
      nStatus = ZwQueryInformationProcess(
            NtCurrentProcess(),
            ProcessImageFileName,
            NULL,
            NULL,
            &nNeedSize
            );

      if (STATUS_INFO_LENGTH_MISMATCH != nStatus)
      {
            KdPrint(("%s NtQueryInformationProcess error.\n",__FUNCTION__));
            nStatus = STATUS_MEMORY_NOT_ALLOCATED;
            __leave;

      }

      lpBuffer = ExAllocatePoolWithTag(NonPagedPool, nNeedSize,'GetP');
      if (lpBuffer == NULL)
      {
            KdPrint(("%s ExAllocatePoolWithTag error.\n",__FUNCTION__));
            nStatus = STATUS_MEMORY_NOT_ALLOCATED;
            __leave;
      }

       nStatus =ZwQueryInformationProcess(
         NtCurrentProcess(),
         ProcessImageFileName,
         lpBuffer,
         nNeedSize,
         &nNeedSize
         );

       if (NT_ERROR(nStatus))
       {
         KdPrint(("%s NtQueryInformationProcess error2.\n",__FUNCTION__));
         __leave;
       }

       RtlCopyUnicodeString(&ProcessPath,(PUNICODE_STRING)lpBuffer);
       InitializeObjectAttributes(
         &ObjectAttributes,
         &ProcessPath,
         OBJ_CASE_INSENSITIVE,
         NULL,
         NULL
         );

       nStatus = ZwCreateFile(
         &hFile,
         FILE_READ_ATTRIBUTES,
         &ObjectAttributes,
         &IoStatus,
         NULL,
         FILE_ATTRIBUTE_NORMAL,
         0,
         FILE_OPEN,
         FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE,
         NULL,
         0
         );

       if (NT_ERROR(nStatus))
       {
         hFile = NULL;
         __leave;
       }

       nStatus = ObReferenceObjectByHandle(
         hFile,
         NULL,
         *IoFileObjectType,
         KernelMode,
         (PVOID*)&FileObject,
         NULL
         );

       if (NT_ERROR(nStatus))
       {
         FileObject = NULL;
         __leave;
       }
      
       FileName = (PFILE_NAME_INFORMATION)FileBuffer;
      
       nStatus = ZwQueryInformationFile(
         hFile,
         &IoStatus,
         FileName,
         sizeof(WCHAR)*MAX_PATH,
         FileNameInformation
         );

       if (NT_ERROR(nStatus))
       {
         __leave;
       }

       if (FileObject->DeviceObject == NULL)
       {
         nDeviceStatus = STATUS_DEVICE_DOES_NOT_EXIST;
         __leave;
       }

       nDeviceStatus = RtlVolumeDeviceToDosName(FileObject->DeviceObject,&DosDeviceName);

    }
    __finally
    {
      if (NULL != FileObject)
      {
            ObDereferenceObject(FileObject);
      }

      if (NULL != hFile)
      {
            ZwClose(hFile);
      }

      if (NULL != lpBuffer)
      {
            ExFreePool(lpBuffer);
      }

      KeUnstackDetachProcess(&ApcState);


    }

    if (NT_SUCCESS(nStatus))
    {
      RtlInitUnicodeString(&ProcessPath,FileName->FileName);

      if (NT_SUCCESS(nDeviceStatus))
      {
            RtlCopyUnicodeString(FullPath,&DosDeviceName);
            RtlUnicodeStringCat(FullPath,&ProcessPath);
      }
      else
      {
            RtlCopyUnicodeString(FullPath,&ProcessPath);
      }
    }


    return nStatus;
}
这实在是太麻烦了

其实要获得全路径 就是要获得FIleObject 而FIleObject就在EPROCESS结构下 详细继续读下去
在NT5上PsReferenceProcessFilePointer没有导出,需要自己实现
在WRK中:

NTSTATUS NTAPI PsReferenceProcessFilePointer      
(
      IN PEPROCESS         Process,
      OUT PFILE_OBJECT *         FileObject
)               
{
    PSECTION Section;
    PAGED_CODE();

    /* Lock the process */
    ExAcquireRundownProtection(&Process->RundownProtect);

    /* Get the section */
    Section = Process->SectionObject;
    if (Section)
    {
      /* Get the file object and reference it */
      *FileObject = MmGetFileObjectForSection((PVOID)Section);
      ObReferenceObject(*FileObject);
    }

    /* Release the protection */
    ExReleaseRundownProtection(&Process->RundownProtect);

    /* Return status */
    return Section ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
}

PFILE_OBJECT NTAPI MmGetFileObjectForSection
(
      IN PVOID         Section
)      
{
    PSECTION_OBJECT Section;
    ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
    ASSERT(SectionObject != NULL);

    /* Check if it's an ARM3, or ReactOS section */
    if (MiIsRosSectionObject(SectionObject) == FALSE)
    {
      /* Return the file pointer stored in the control area */
      Section = SectionObject;
      return Section->Segment->ControlArea->FilePointer;
    }

    /* Return the file object */
    return ((PROS_SECTION_OBJECT)SectionObject)->FileObject;
}
FileObject要这么获得:Process->SectionObject->Segment->ControlArea->FilePointer

大概需要4个硬编码
XP:
code:

//Process->SectionObject->Segment->ControlArea->FilePointer
PFILE_OBJECT __declspec(naked) __stdcall _MmGetFileObjectForSection(PVOID Section)
{
    __asm
    {
      push ebp;
      movebp, esp;
      moveax, dword ptr ss:;
      moveax, dword ptr ds:;
      moveax, dword ptr ds:;
      moveax, dword ptr ds:;
      movesp, ebp;
      popebp;
      ret0x04;
    }
        /*
        kd> dt _section_object 0xe109e640
nt!_SECTION_OBJECT
   +0x000 StartingVa       : (null)
   +0x004 EndingVa         : (null)
   +0x008 Parent         : (null)
   +0x00c LeftChild      : (null)
   +0x010 RightChild       : (null)
   +0x014 Segment          : 0xe10c14c0 _SEGMENT_OBJECT
kd> dt _SEGMENT_OBJECT 0xe10c14c0
nt!_SEGMENT_OBJECT
   +0x000 BaseAddress      : 0x861f2348 Void
   +0x004 TotalNumberOfPtes : 0xb1
   +0x008 SizeOfSegment    : _LARGE_INTEGER 0xb1
   +0x010 NonExtendedPtes: 0xb1000
   +0x014 ImageCommitment: 0
   +0x018 ControlArea      : 0xcbf13c3e _CONTROL_AREA
   +0x01c Subsection       : (null)
   +0x020 LargeControlArea : (null)
   +0x024 MmSectionFlags   : (null)
   +0x028 MmSubSectionFlags : 0x00400000 _MMSUBSECTION_FLAGS
kd> dt _CONTROL_AREA 0x861f2348
nt!_CONTROL_AREA
   +0x000 Segment          : 0xe10c14c0 _SEGMENT
   +0x004 DereferenceList: _LIST_ENTRY [ 0x0 - 0x0 ]
   +0x00c NumberOfSectionReferences : 1
   +0x010 NumberOfPfnReferences : 0xa1
   +0x014 NumberOfMappedViews : 1
   +0x018 NumberOfSubsections : 5
   +0x01a FlushInProgressCount : 0
   +0x01c NumberOfUserReferences : 2
   +0x020 u                : __unnamed
   +0x024 FilePointer      : 0x8602caf8 _FILE_OBJECT
   +0x028 WaitingForDeletion : (null)
   +0x02c ModifiedWriteCount : 0
   +0x02e NumberOfSystemCacheViews : 0
kd> dt _FILE_OBJECT 0x8602caf8
nt!_FILE_OBJECT
   +0x000 Type             : 0n5
   +0x002 Size             : 0n112
   +0x004 DeviceObject   : 0x8632c030 _DEVICE_OBJECT
   +0x008 Vpb            : 0x862443c8 _VPB
   +0x00c FsContext      : 0xe1059aa0 Void
   +0x010 FsContext2       : 0xe105b648 Void
   +0x014 SectionObjectPointer : 0x85e16fa0 _SECTION_OBJECT_POINTERS
   +0x018 PrivateCacheMap: (null)
   +0x01c FinalStatus      : 0n0
   +0x020 RelatedFileObject : (null)
   +0x024 LockOperation    : 0 ''
   +0x025 DeletePending    : 0 ''
   +0x026 ReadAccess       : 0x1 ''
   +0x027 WriteAccess      : 0 ''
   +0x028 DeleteAccess   : 0 ''
   +0x029 SharedRead       : 0x1 ''
   +0x02a SharedWrite      : 0 ''
   +0x02b SharedDelete   : 0x1 ''
   +0x02c Flags            : 0xc4042
   +0x030 FileName         : _UNICODE_STRING "\Program Files\VMware\VMware Tools\TPAutoConnect.exe"
   +0x038 CurrentByteOffset : _LARGE_INTEGER 0x0
   +0x040 Waiters          : 0
   +0x044 Busy             : 0
   +0x048 LastLock         : (null)
   +0x04c Lock             : _KEVENT
   +0x05c Event            : _KEVENT
   +0x06c CompletionContext : (null)

        */
}

NTSTATUS PsReferenceProcessFilePointer(IN PEPROCESS Process, OUT PVOID *OutFileObject)
{
    PVOID SectionObject;
        //xp:
        // +0x134 Job            : Ptr32 _EJOB
        // +0x138 SectionObject    : Ptr32 Void
    if (SectionObject = *(PVOID*)((PCHAR)Process + 0x138))
    {
      PFILE_OBJECT FileObject;

      FileObject = _MmGetFileObjectForSection(SectionObject);
      *OutFileObject = FileObject;
      ObReferenceObject (FileObject);
      return STATUS_SUCCESS;
    }
    return STATUS_UNSUCCESSFUL;
}

PUNICODE_STRING PsGetProcessFullNameByHardCodeOfXP(PEPROCESS pTargetProcess)
{
      PFILE_OBJECT pFileObject=NULL;
      POBJECT_NAME_INFORMATION pObjectNameInfo=NULL;
                if(!NT_SUCCESS(PsReferenceProcessFilePointer(pTargetProcess,&pFileObject)))
                return NULL;
      if(!NT_SUCCESS(IoQueryFileDosDeviceName(pFileObject,&pObjectNameInfo)))
                return NULL;
      return &(pObjectNameInfo->Name);//尚未释放内存
}
除了这个以外:还有一个

Process->SeAuditProcessCreationInfo.ImageFileName->Name


在WRK中可以看到
这说明从这个路径可能是不存在的

NTSTATUS
SeLocateProcessImageName(
    __in PEPROCESS Process,
    __deref_out PUNICODE_STRING *pImageFileName
    )


/*++


Routine Description
   
    This routine returns the ImageFileName information from the process, if available.This is a "lazy evaluation" wrapper
    around SeInitializeProcessAuditName.If the image file name information has already been computed, then this call simply
    allocates and returns a UNICODE_STRING with this information.Otherwise, the function determines the name, stores the name in the
    EPROCESS structure, and then allocates and returns a UNICODE_STRING.Caller must free the memory returned in pImageFileName.
   
Arguments


    Process - process for which to acquire the name
   
    pImageFileName - output parameter to return name to caller
   
Return Value


    NTSTATUS.
   
--*/


{
    NTSTATUS               Status            = STATUS_SUCCESS;
    PVOID                  FilePointer       = NULL;
    PVOID                  PreviousValue   = NULL;
    POBJECT_NAME_INFORMATION pProcessImageName = NULL;
    PUNICODE_STRING          pTempUS         = NULL;
    ULONG                  NameLength      = 0;


    PAGED_CODE();


    *pImageFileName = NULL;
   
    if (NULL == Process->SeAuditProcessCreationInfo.ImageFileName) {


      //
      // The name has not been predetermined.We must determine the process name.   First, reference the
      // PFILE_OBJECT and lookup the name.Then again check the process image name pointer against NULL.
      // Finally, set the name.
      //


      Status = PsReferenceProcessFilePointer( Process, &FilePointer );
      
      if (NT_SUCCESS(Status)) {


            //
            // Get the process name information.
            //


            Status = SeInitializeProcessAuditName(
                        FilePointer,
                        TRUE, // skip audit policy
                        &pProcessImageName // to be allocated in nonpaged pool
                        );


            if (NT_SUCCESS(Status)) {


                //
                // Only use the pProcessImageName if the field in the process is currently NULL.
                //


                PreviousValue = InterlockedCompareExchangePointer(
                                    (PVOID *) &Process->SeAuditProcessCreationInfo.ImageFileName,
                                    (PVOID) pProcessImageName,
                                    (PVOID) NULL
                                    );
               
                if (NULL != PreviousValue) {
                  ExFreePool(pProcessImageName); // free what we caused to be allocated.
                }
            }
            ObDereferenceObject( FilePointer );
      }
    }
   
   
    if (NT_SUCCESS(Status)) {
      
      //
      // Allocate space for a buffer to contain the name for returning to the caller.
      //


      NameLength = sizeof(UNICODE_STRING) + Process->SeAuditProcessCreationInfo.ImageFileName->Name.MaximumLength;
      pTempUS = ExAllocatePoolWithTag( NonPagedPool, NameLength, 'aPeS' );


      if (NULL != pTempUS) {


            RtlCopyMemory(
                pTempUS,
                &Process->SeAuditProcessCreationInfo.ImageFileName->Name,
                NameLength
                );


            pTempUS->Buffer = (PWSTR)(((PUCHAR) pTempUS) + sizeof(UNICODE_STRING));
            *pImageFileName = pTempUS;


      } else {
            
            Status = STATUS_NO_MEMORY;
      }
    }


    return Status;
}

我自己实现了下 在win7 x86下效果还是可以的 不过使用了硬编码,推荐还是在NT5上使用(NT6很简单)


PUNICODE_STRING GetSeLocateProcessImageName(PEPROCESS Process,PUNICODE_STRING *pImageFileName)
{
       POBJECT_NAME_INFORMATION pProcessImageName = NULL;
       PUNICODE_STRING pTempUS = NULL;
       ULONG NameLength = 0;
       //Process->SeAuditProcessCreationInfo.ImageFileName->Name
       //win7 x86 offset = 0x1ec
       //if (NULL == Process->SeAuditProcessCreationInfo.ImageFileName)
       pProcessImageName = (POBJECT_NAME_INFORMATION)(*(ULONG*)((ULONG)Process + 0x1ec));
       if(pProcessImageName == NULL)
       {
               DbgPrint("Process->SeAuditProcessCreationInfo.ImageFileName == NULL \n");
               return NULL;
       }
       else
       {
               NameLength = sizeof(UNICODE_STRING) + pProcessImageName->Name.MaximumLength;
               pTempUS = ExAllocatePoolWithTag( NonPagedPool, NameLength, 'aPeS' );
               if (NULL != pTempUS) {

            RtlCopyMemory(
                pTempUS,
                                &pProcessImageName->Name,
                NameLength
                );

            pTempUS->Buffer = (PWSTR)(((PUCHAR) pTempUS) + sizeof(UNICODE_STRING));
            *pImageFileName = pTempUS;
                       DbgPrint("Path:%wZ\n",&pProcessImageName->Name);
                       return *pImageFileName;
               }
               return NULL;
       }

}



而NT6就很简单了
PsReferenceProcessFilePointe已经被导出了
那么直接使用
PsReferenceProcessFilePointe +IoQueryFileDosDeviceName就可以了

PUNICODE_STRING PsGetProcessFullName(PEPROCESS pTargetProcess)
{
      PFILE_OBJECT pFileObject=NULL;
      POBJECT_NAME_INFORMATION pObjectNameInfo=NULL;
                if(!NT_SUCCESS(PsReferenceProcessFilePointer(pTargetProcess,&pFileObject)))
                return NULL;
      if(!NT_SUCCESS(IoQueryFileDosDeviceName(pFileObject,&pObjectNameInfo)))
                return NULL;
      return &(pObjectNameInfo->Name);//尚未释放内存 以及 ObDereferenceObject
}


除了这些以前还有一些路径存在PEB里 如果在x64的系统中 还得看是PEB32还是PEB64 虽然可以使用PsGetProcessWow64Process来判断是不是64进程
但这些数据在r3就可以直接被修改了 所以不太建议使用
PEB->ProcessParameters->ImagePathName
PEB->ProcessParameters->CommandLine
PEB->ProcessParameters->WindowTitle
PEB->Ldr->InLoadOrderLinks->FullDllName
PEB->Ldr->InMemoryOrderLinks->FullDllName


大家看看黑客防线里面的《伪造进程初探》和获取进程完整路径方法小结.pdf
另外一个博主写的也是不错的
42969803 //EPROCESS取进程全路径
43638651 //EPROCESS取进程全路径(xp)
页: [1]
查看完整版本: NT5/NT6上的获取进程全路径