在得到進程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 }