驱动层得到进程的完整路径

   在得到进程EProcess之后,对于进程完整路径的获得一般有两种方法,一种是访问的进程的PEB结构,在PEB结构中保存有进程的完整路径,另一种方法就是采用访问_FILE_OBJECT的方法。

  访问PEB的方法便存在线程靠挂的问题,因为运行于Ring0层的线程是无法去访问用户地址空间的,需要将线程暂时靠挂到目标呢进程,进而去访问进程的PEB结构。我一般都采用的访问_FILE_OBJECT的方法,避免了线程的靠挂问题,而且访问peb的方法会存在一个问题:如果想要进行进程拦截,在进程未启动之前就阻止进程的启动,此时进程空间还未开辟,peb结构都不存在,只能去访问exe文件在ring0层的文件对象,通过文件对象来获得进程的完整路径。

  进程靠挂函数原型

1 VOID KeStackAttachProcess (
2     PKPROCESS  Process,
3     PRKAPC_STATE  ApcState
4     );

访问目标进程的用户地址空间之后返回ring0运行调用函数

VOID KeUnstackDetachProcess(
   PRKAPC_STATE  ApcState
    );

kd> dt _eprocess

+0x1b0 Peb              : Ptr32 _PEB    //X86 Peb在EProcess中的偏移量

kd> dt _peb

+0x00c Ldr              : Ptr32 _PEB_LDR_DATA        ;进程加载的模块链表

关于进程加载模块链表是有三条链表

InLoadOrderModuleList    //模块的加载顺序

InMemoryOrderModuleList   // 模块在内存中的顺序

InInitializationOrderModuleList   // 模块的初始化顺序

进程的第一模块就是exe文件,对于exe的路径就是取InLoadOrderModuleList 中的第一模块的FullDllName。

 

第二种方法,用_FILE_OBJECT 的方法

以下为Windbg的调试过程,在虚拟机中打开calc.exe然后获得calc.exe的完整路径

Win7 X64

1 kd> !process 0 0
2 
3 PROCESS fffffa801a619b30
4     SessionId: 1  Cid: 0b10    Peb: 7fffffd6000  ParentCid: 05fc
5     DirBase: 5f017000  ObjectTable: fffff8a00296ac00  HandleCount:  79.
6     Image: calc.exe

kd> dt _eprocess fffffa801a619b30

+0x268 SectionObject    : 0xfffff8a0`01ba1f30 Void


kd> dt _section_object 0xfffff8a0`01ba1f30
nt!_SECTION_OBJECT
+0x000 StartingVa : (null)
+0x008 EndingVa : 0xfffff880`03bd4ba8 Void
+0x010 Parent : 0xfffff880`03bd4b90 Void
+0x018 LeftChild : (null)
+0x020 RightChild : 0xfffffa80`19e84300 Void
+0x028 Segment : 0xfffff8a0`01b19850 _SEGMENT_OBJECT


  

kd> dt _segment 0xfffff8a0`01b19850
nt!_SEGMENT
+0x000 ControlArea : 0xfffffa80`1a687d30 _CONTROL_AREA
+0x008 TotalNumberOfPtes : 0xe3
+0x00c SegmentFlags : _SEGMENT_FLAGS
+0x010 NumberOfCommittedPages : 0
+0x018 SizeOfSegment : 0xe3000
+0x020 ExtendInfo : 0x00000000`ffbf0000 _MMEXTEND_INFO
+0x020 BasedAddress : 0x00000000`ffbf0000 Void
+0x028 SegmentLock : _EX_PUSH_LOCK
+0x030 u1 : <unnamed-tag>
+0x038 u2 : <unnamed-tag>
+0x040 PrototypePte : 0xfffff8a0`01b19898 _MMPTE
+0x048 ThePtes : [1] _MMPTE

 

kd> dt _CONTROL_AREA 0xfffffa80`1a687d30
nt!_CONTROL_AREA
+0x000 Segment : 0xfffff8a0`01b19850 _SEGMENT
+0x008 DereferenceList : _LIST_ENTRY [ 0x00000000`00000000 – 0xfffffa80`1a8a1018 ]
+0x018 NumberOfSectionReferences : 1
+0x020 NumberOfPfnReferences : 0x97
+0x028 NumberOfMappedViews : 1
+0x030 NumberOfUserReferences : 2
+0x038 u : <unnamed-tag>
+0x03c FlushInProgressCount : 0
+0x040 FilePointer : _EX_FAST_REF       //与X86的不同,X86下FilePointer的类型为_FILE_OBJECT,X64加了一层封装

 

kd> dt _EX_FAST_REF 0xfffffa80`1a687d30+0x040
nt!_EX_FAST_REF
+0x000 Object : 0xfffffa80`1a685073 Void         //真正的_FILE_OBJECT 最后一位要进行清0操作,  文件对象的最后一位必然为0
+0x000 RefCnt : 0y0011
+0x000 Value : 0xfffffa80`1a685073

 

 

kd> dt _File_object 0xfffffa80`1a685070 //_File_Object 最后一位清0
nt!_FILE_OBJECT
+0x000 Type : 0n5
+0x002 Size : 0n216
+0x008 DeviceObject : 0xfffffa80`19376530 _DEVICE_OBJECT
+0x010 Vpb : 0xfffffa80`19376470 _VPB
+0x018 FsContext : 0xfffff8a0`000f5140 Void
+0x020 FsContext2 : 0xfffff8a0`019715d0 Void
+0x028 SectionObjectPointer : 0xfffffa80`19e5ec88 _SECTION_OBJECT_POINTERS
+0x030 PrivateCacheMap : (null)
+0x038 FinalStatus : 0n0
+0x040 RelatedFileObject : (null)
+0x048 LockOperation : 0 ”
+0x049 DeletePending : 0 ”
+0x04a ReadAccess : 0x1 ”
+0x04b WriteAccess : 0 ”
+0x04c DeleteAccess : 0 ”
+0x04d SharedRead : 0x1 ”
+0x04e SharedWrite : 0 ”
+0x04f SharedDelete : 0x1 ”
+0x050 Flags : 0x44042
+0x058 FileName : _UNICODE_STRING “\Windows\System32\calc.exe”                                    //完整路径
+0x068 CurrentByteOffset : _LARGE_INTEGER 0x0
+0x070 Waiters : 0
+0x074 Busy : 0
+0x078 LastLock : (null)
+0x080 Lock : _KEVENT
+0x098 Event : _KEVENT
+0x0b0 CompletionContext : (null)
+0x0b8 IrpListLock : 0
+0x0c0 IrpList : _LIST_ENTRY [ 0xfffffa80`1a685130 – 0xfffffa80`1a685130 ]
+0x0d0 FileObjectExtension : (null)

 

 

 

 

 

 

WinXP X86

kd> !process 0 0

PROCESS 8971d6f8 SessionId: 0 Cid: 0378 Peb: 7ffdc000 ParentCid: 0664
DirBase: 0f8c02a0 ObjectTable: e23027a8 HandleCount: 44.
Image: calc.exe

kd> dt _eprocess 8971d6f8

+0x138 SectionObject : 0xe22963d0 Void

kd> dt _section_object 0xe22963d0
nt!_SECTION_OBJECT
+0x000 StartingVa : (null)
+0x004 EndingVa : (null)
+0x008 Parent : (null)
+0x00c LeftChild : (null)
+0x010 RightChild : (null)
+0x014 Segment : 0xe18e4820 _SEGMENT_OBJECT

kd> dt _segment 0xe18e4820
nt!_SEGMENT
+0x000 ControlArea : 0x89769478 _CONTROL_AREA
+0x004 TotalNumberOfPtes : 0x1f
+0x008 NonExtendedPtes : 0x1f
+0x00c WritableUserReferences : 0
+0x010 SizeOfSegment : 0x1f000
+0x018 SegmentPteTemplate : _MMPTE
+0x020 NumberOfCommittedPages : 0
+0x024 ExtendInfo : (null)
+0x028 SystemImageBase : (null)
+0x02c BasedAddress : 0x01000000 Void
+0x030 u1 : __unnamed
+0x034 u2 : __unnamed
+0x038 PrototypePte : 0xe18e4860 _MMPTE
+0x040 ThePtes : [1] _MMPTE

kd> dt _CONTROL_AREA 0x89769478
nt!_CONTROL_AREA
+0x000 Segment : 0xe18e4820 _SEGMENT
+0x004 DereferenceList : _LIST_ENTRY [ 0x0 – 0x0 ]
+0x00c NumberOfSectionReferences : 1
+0x010 NumberOfPfnReferences : 0x1d
+0x014 NumberOfMappedViews : 1
+0x018 NumberOfSubsections : 4
+0x01a FlushInProgressCount : 0
+0x01c NumberOfUserReferences : 2
+0x020 u : __unnamed
+0x024 FilePointer : 0x8958a9b0 _FILE_OBJECT
+0x028 WaitingForDeletion : (null)
+0x02c ModifiedWriteCount : 0
+0x02e NumberOfSystemCacheViews : 0

kd> dt _FILE_OBJECT 0x8958a9b0
nt!_FILE_OBJECT
+0x000 Type : 0n5
+0x002 Size : 0n112
+0x004 DeviceObject : 0x899ab900 _DEVICE_OBJECT
+0x008 Vpb : 0x8994c1d8 _VPB                               //卷参数块,由此得到所属卷设备,即盘符
+0x00c FsContext : 0xe228f710 Void
+0x010 FsContext2 : 0xe1f5ea90 Void
+0x014 SectionObjectPointer : 0x894bbbe4 _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 : 0x44042
+0x030 FileName : _UNICODE_STRING “\WINDOWS\system32\calc.exe”                            //完整路径
+0x038 CurrentByteOffset : _LARGE_INTEGER 0x0
+0x040 Waiters : 0
+0x044 Busy : 0
+0x048 LastLock : (null)
+0x04c Lock : _KEVENT
+0x05c Event : _KEVENT
+0x06c CompletionContext : (null)

 结构体的定义

ypedef struct _CONTROL_AREA64
{
    PVOID64 Segment;
    PVOID64 p1;
    PVOID64 p2;
    ULONG64 NumberOfSectionReferences;
    ULONG64 NumberOfPfnReferences;
    ULONG64 NumberOfMappedViews;
    ULONG64 NumberOfUserReferences;
    union
    {
        ULONG LongFlags;
        ULONG Flags;
    } u;
    PVOID64 FilePointer;
} CONTROL_AREA64, *PCONTROL_AREA64;

typedef struct _CONTROL_AREA
{
    PVOID Segment;
    LIST_ENTRY DereferenceList;
    ULONG NumberOfSectionReferences;
    ULONG NumberOfPfnReferences;
    ULONG NumberOfMappedViews;
    ULONG NumberOfSystemCacheViews;
    ULONG NumberOfUserReferences;
    union
    {
        ULONG LongFlags;
        ULONG Flags;
    } u;
    PFILE_OBJECT FilePointer;
} CONTROL_AREA, *PCONTROL_AREA;


typedef struct _SEGMENT64
{
    PVOID64 ControlArea;
    ULONG TotalNumberOfPtes;
    ULONG NonExtendedPtes;
    ULONG Spare0;
}SEGMENT64,*PSEGMENT64;

typedef struct _SEGMENT
{
    struct _CONTROL_AREA *ControlArea;
    ULONG TotalNumberOfPtes;
    ULONG NonExtendedPtes;
    ULONG Spare0;
} SEGMENT, *PSEGMENT;


typedef struct _SECTION_OBJECT
{
    PVOID StartingVa;
    PVOID EndingVa;
    PVOID Parent;
    PVOID LeftChild;
    PVOID RightChild;
    PSEGMENT Segment;
} SECTION_OBJECT, *PSECTION_OBJECT;


typedef struct _SECTION_OBJECT64
{
    PVOID64 StartingVa;
    PVOID64 EndingVa;
    PVOID64 Parent;
    PVOID64 LeftChild;
    PVOID64 RightChild;
    PVOID64 Segment;
} SECTION_OBJECT64, *PSECTION_OBJECT64;

 

 

BOOLEAN
GetProcessPathBySectionObject(ULONG_PTR ulProcessID,WCHAR* wzProcessPath)
{
    PEPROCESS         EProcess = NULL;
    PSECTION_OBJECT   SectionObject   = NULL;
    PSECTION_OBJECT64 SectionObject64 = NULL;
    PSEGMENT        Segment   = NULL;
    PSEGMENT64      Segment64 = NULL;
    PCONTROL_AREA   ControlArea = NULL;
    PCONTROL_AREA64 ControlArea64 = NULL;
    PFILE_OBJECT    FileObject  = NULL;
    BOOLEAN         bGetPath = FALSE;

    if (NT_SUCCESS(PsLookupProcessByProcessId((HANDLE)ulProcessID, &EProcess)))
    {

        switch(WinVersion)
        {
        case WINDOWS_XP:   //x86 XP sp3
            {
                SectionObjectOfEProcess  = 0x138;
                if (SectionObjectOfEProcess!=0&&MmIsAddressValid((PVOID)((ULONG_PTR)EProcess + SectionObjectOfEProcess)))
                {
                    SectionObject = *(PSECTION_OBJECT*)((ULONG_PTR)EProcess + SectionObjectOfEProcess);
                    if (SectionObject && MmIsAddressValid(SectionObject))
                    {
                        Segment = (PSEGMENT)SectionObject->Segment;
                        if (Segment && MmIsAddressValid(Segment))
                        {
                            ControlArea = Segment->ControlArea;
                            if (ControlArea && MmIsAddressValid(ControlArea))
                            {
                                FileObject = ControlArea->FilePointer;
                                if (FileObject&&MmIsAddressValid(FileObject))
                                {
                                    bGetPath = GetPathByFileObject(FileObject, wzProcessPath);
                                    if (!bGetPath)
                                    {
                                        DbgPrint("SectionObject: 0x%08X, FileObject: 0x%08X\n", SectionObject, FileObject);
                                    }
                                }
                            }
                        }
                    }
                }
                break;
            }

        case WINDOWS_7:  //Win 7 x64 sp1
            {    
                SectionObjectOfEProcess = 0x268;           
                if (SectionObjectOfEProcess!=0&&MmIsAddressValid((PVOID)((ULONG_PTR)EProcess + SectionObjectOfEProcess)))
                {
                    SectionObject64 = *(PSECTION_OBJECT64*)((ULONG_PTR)EProcess + SectionObjectOfEProcess);
                    if (SectionObject64 && MmIsAddressValid(SectionObject64))
                    {

                        Segment64 = (PSEGMENT64)(SectionObject64->Segment);
                        if (Segment64 && MmIsAddressValid(Segment64))
                        {
                            ControlArea64 = (PCONTROL_AREA64)Segment64->ControlArea;
                            if (ControlArea64 && MmIsAddressValid(ControlArea64))
                            {
                                FileObject = (PFILE_OBJECT)ControlArea64->FilePointer;
                                if (FileObject&&MmIsAddressValid(FileObject))
                                {
                                    FileObject = (PFILE_OBJECT)((ULONG_PTR)FileObject & 0xFFFFFFFFFFFFFFF0);
                                    bGetPath = GetPathByFileObject(FileObject, wzProcessPath);
                                    if (!bGetPath)
                                    {
                                        DbgPrint("SectionObject: 0x%08X, FileObject: 0x%08X\n", SectionObject, FileObject);
                                    }
                                }
                            }
                        }
                    }
                }
                break;
            }
        }        
    }
    if (bGetPath==FALSE)
    {
        wcscpy(wzProcessPath,L"Unknow");
    }

    return bGetPath;    

}

 

获得文件对象以后,获得完整的路径

//传入文件对象,返回完整路径

  1 BOOLEAN GetPathByFileObject(PFILE_OBJECT FileObject, WCHAR* wzPath)
  2 {
  3     BOOLEAN bGetPath = FALSE;
  4     CHAR szIoQueryFileDosDeviceName[] = "IoQueryFileDosDeviceName";
  5     CHAR szIoVolumeDeviceToDosName[] = "IoVolumeDeviceToDosName";
  6     CHAR szRtlVolumeDeviceToDosName[] = "RtlVolumeDeviceToDosName";
  7 
  8     POBJECT_NAME_INFORMATION ObjectNameInformation = NULL;
  9     __try
 10     {
 11         if (FileObject && MmIsAddressValid(FileObject) && wzPath)
 12         {
 13         
 14             if (NT_SUCCESS(IoQueryFileDosDeviceName(FileObject,&ObjectNameInformation)))   //注意该函数调用后要释放内存
 15             {
 16                 wcsncpy(wzPath,ObjectNameInformation->Name.Buffer,ObjectNameInformation->Name.Length);
 17 
 18                 bGetPath = TRUE;
 19 
 20                 ExFreePool(ObjectNameInformation);
 21             }
 22             
 23             
 24             if (!bGetPath)
 25             {
 26             
 27                 if (IoVolumeDeviceToDosName||RtlVolumeDeviceToDosName)
 28                 {
 29                     NTSTATUS  Status = STATUS_UNSUCCESSFUL;
 30                     ULONG_PTR ulRet= 0;
 31                     PVOID     Buffer = ExAllocatePool(PagedPool,0x1000);
 32 
 33                     if (Buffer)
 34                     {
 35                         // ObQueryNameString : \Device\HarddiskVolume1\Program Files\VMware\VMware Tools\VMwareTray.exe
 36                         memset(Buffer, 0, 0x1000);
 37                         Status = ObQueryNameString(FileObject, (POBJECT_NAME_INFORMATION)Buffer, 0x1000, &ulRet);
 38                         if (NT_SUCCESS(Status))
 39                         {
 40                             POBJECT_NAME_INFORMATION Temp = (POBJECT_NAME_INFORMATION)Buffer;
 41                         
 42                             WCHAR szHarddiskVolume[100] = L"\\Device\\HarddiskVolume";
 43 
 44                             if (Temp->Name.Buffer!=NULL)
 45                             {
 46                                 if (Temp->Name.Length / sizeof(WCHAR) > wcslen(szHarddiskVolume) &&
 47                                     !_wcsnicmp(Temp->Name.Buffer, szHarddiskVolume, wcslen(szHarddiskVolume)))
 48                                 {
 49                                     // 如果是以 "\\Device\\HarddiskVolume" 这样的形式存在的,那么再查询其卷名。
 50                                     UNICODE_STRING uniDosName;
 51 
 52                                     if (NT_SUCCESS(IoVolumeDeviceToDosName(FileObject->DeviceObject, &uniDosName)))
 53                                     {
 54                                         if (uniDosName.Buffer!=NULL)
 55                                         {
 56                                         
 57                                             wcsncpy(wzPath, uniDosName.Buffer, uniDosName.Length);
 58                                             wcsncat(wzPath, Temp->Name.Buffer + wcslen(szHarddiskVolume) + 1, Temp->Name.Length - (wcslen(szHarddiskVolume) + 1));
 59                                             bGetPath = TRUE;
 60                                         }    
 61 
 62                                         ExFreePool(uniDosName.Buffer);
 63                                     }
 64 
 65                                     else if (NT_SUCCESS(RtlVolumeDeviceToDosName(FileObject->DeviceObject, &uniDosName)))
 66                                     {
 67                                         if (uniDosName.Buffer!=NULL)
 68                                         {
 69 
 70                                             wcsncpy(wzPath, uniDosName.Buffer, uniDosName.Length);
 71                                             wcsncat(wzPath, Temp->Name.Buffer + wcslen(szHarddiskVolume) + 1, Temp->Name.Length - (wcslen(szHarddiskVolume) + 1));
 72                                             bGetPath = TRUE;
 73                                         }    
 74 
 75                                         ExFreePool(uniDosName.Buffer);
 76                                     }
 77                                     
 78                                 }
 79                                 else
 80                                 {
 81                                     // 如果不是以 "\\Device\\HarddiskVolume" 这样的形式开头的,那么直接复制名称。
 82                                     
 83                                     wcsncpy(wzPath, Temp->Name.Buffer, Temp->Name.Length);
 84                                     bGetPath = TRUE;
 85                                 }
 86                             }
 87                         }
 88 
 89                         ExFreePool(Buffer);
 90                     }
 91                 }
 92             }
 93         }
 94     }
 95     __except(1)
 96     {
 97         DbgPrint("GetPathByFileObject Catch __Except\r\n");
 98         bGetPath = FALSE;
 99     }
100 
101     return bGetPath;
102 }

 

点赞