UID 3808
精华
积分 1480
威望 点
宅币 个
贡献 次
宅之契约 份
最后登录 1970-1-1
在线时间 小时
本程序理解上收到了群MinL同学的指导,非常感谢!
内核中PEB块和LDR链用处非常多,常见的用处比如就是本贴要讨论的遍历制定进程的模块;
实验环境:Visual Studio 2013,WDK8.1,Windows 7 x64虚拟机,Windbg,DbgView,KMDmanager。
首先我们用Windbg看一下EPROCESS,PEB在EPROCESS中是以PPEB指针形式作为成员变量的:
EPROCESS结构体:
kd> dt _EPROCESS
nt!_EPROCESS
+0x000 Pcb : _KPROCESS
+0x160 ProcessLock : _EX_PUSH_LOCK
+0x168 CreateTime : _LARGE_INTEGER
+0x170 ExitTime : _LARGE_INTEGER
+0x178 RundownProtect : _EX_RUNDOWN_REF
+0x180 UniqueProcessId : Ptr64 Void
+0x188 ActiveProcessLinks : _LIST_ENTRY
+0x198 ProcessQuotaUsage : [2] Uint8B
+0x1a8 ProcessQuotaPeak : [2] Uint8B
+0x1b8 CommitCharge : Uint8B
+0x1c0 QuotaBlock : Ptr64 _EPROCESS_QUOTA_BLOCK
+0x1c8 CpuQuotaBlock : Ptr64 _PS_CPU_QUOTA_BLOCK
+0x1d0 PeakVirtualSize : Uint8B
+0x1d8 VirtualSize : Uint8B
+0x1e0 SessionProcessLinks : _LIST_ENTRY
+0x1f0 DebugPort : Ptr64 Void
+0x1f8 ExceptionPortData : Ptr64 Void
+0x1f8 ExceptionPortValue : Uint8B
+0x1f8 ExceptionPortState : Pos 0, 3 Bits
+0x200 ObjectTable : Ptr64 _HANDLE_TABLE
+0x208 Token : _EX_FAST_REF
+0x210 WorkingSetPage : Uint8B
+0x218 AddressCreationLock : _EX_PUSH_LOCK
+0x220 RotateInProgress : Ptr64 _ETHREAD
+0x228 ForkInProgress : Ptr64 _ETHREAD
+0x230 HardwareTrigger : Uint8B
+0x238 PhysicalVadRoot : Ptr64 _MM_AVL_TABLE
+0x240 CloneRoot : Ptr64 Void
+0x248 NumberOfPrivatePages : Uint8B
+0x250 NumberOfLockedPages : Uint8B
+0x258 Win32Process : Ptr64 Void
+0x260 Job : Ptr64 _EJOB
+0x268 SectionObject : Ptr64 Void
+0x270 SectionBaseAddress : Ptr64 Void
+0x278 Cookie : Uint4B
+0x27c UmsScheduledThreads : Uint4B
+0x280 WorkingSetWatch : Ptr64 _PAGEFAULT_HISTORY
+0x288 Win32WindowStation : Ptr64 Void
+0x290 InheritedFromUniqueProcessId : Ptr64 Void
+0x298 LdtInformation : Ptr64 Void
+0x2a0 Spare : Ptr64 Void
+0x2a8 ConsoleHostProcess : Uint8B
+0x2b0 DeviceMap : Ptr64 Void
+0x2b8 EtwDataSource : Ptr64 Void
+0x2c0 FreeTebHint : Ptr64 Void
+0x2c8 FreeUmsTebHint : Ptr64 Void
+0x2d0 PageDirectoryPte : _HARDWARE_PTE
+0x2d0 Filler : Uint8B
+0x2d8 Session : Ptr64 Void
+0x2e0 ImageFileName : [15] UChar
+0x2ef PriorityClass : UChar
+0x2f0 JobLinks : _LIST_ENTRY
+0x300 LockedPagesList : Ptr64 Void
+0x308 ThreadListHead : _LIST_ENTRY
+0x318 SecurityPort : Ptr64 Void
+0x320 Wow64Process : Ptr64 Void
+0x328 ActiveThreads : Uint4B
+0x32c ImagePathHash : Uint4B
+0x330 DefaultHardErrorProcessing : Uint4B
+0x334 LastThreadExitStatus : Int4B
+0x338 Peb : Ptr64 _PEB
+0x340 PrefetchTrace : _EX_FAST_REF
+0x348 ReadOperationCount : _LARGE_INTEGER
+0x350 WriteOperationCount : _LARGE_INTEGER
+0x358 OtherOperationCount : _LARGE_INTEGER
+0x360 ReadTransferCount : _LARGE_INTEGER
+0x368 WriteTransferCount : _LARGE_INTEGER
+0x370 OtherTransferCount : _LARGE_INTEGER
+0x378 CommitChargeLimit : Uint8B
+0x380 CommitChargePeak : Uint8B
+0x388 AweInfo : Ptr64 Void
+0x390 SeAuditProcessCreationInfo : _SE_AUDIT_PROCESS_CREATION_INFO
+0x398 Vm : _MMSUPPORT
+0x420 MmProcessLinks : _LIST_ENTRY
+0x430 HighestUserAddress : Ptr64 Void
+0x438 ModifiedPageCount : Uint4B
+0x43c Flags2 : Uint4B
+0x43c JobNotReallyActive : Pos 0, 1 Bit
+0x43c AccountingFolded : Pos 1, 1 Bit
+0x43c NewProcessReported : Pos 2, 1 Bit
+0x43c ExitProcessReported : Pos 3, 1 Bit
+0x43c ReportCommitChanges : Pos 4, 1 Bit
+0x43c LastReportMemory : Pos 5, 1 Bit
+0x43c ReportPhysicalPageChanges : Pos 6, 1 Bit
+0x43c HandleTableRundown : Pos 7, 1 Bit
+0x43c NeedsHandleRundown : Pos 8, 1 Bit
+0x43c RefTraceEnabled : Pos 9, 1 Bit
+0x43c NumaAware : Pos 10, 1 Bit
+0x43c ProtectedProcess : Pos 11, 1 Bit
+0x43c DefaultPagePriority : Pos 12, 3 Bits
+0x43c PrimaryTokenFrozen : Pos 15, 1 Bit
+0x43c ProcessVerifierTarget : Pos 16, 1 Bit
+0x43c StackRandomizationDisabled : Pos 17, 1 Bit
+0x43c AffinityPermanent : Pos 18, 1 Bit
+0x43c AffinityUpdateEnable : Pos 19, 1 Bit
+0x43c PropagateNode : Pos 20, 1 Bit
+0x43c ExplicitAffinity : Pos 21, 1 Bit
+0x440 Flags : Uint4B
+0x440 CreateReported : Pos 0, 1 Bit
+0x440 NoDebugInherit : Pos 1, 1 Bit
+0x440 ProcessExiting : Pos 2, 1 Bit
+0x440 ProcessDelete : Pos 3, 1 Bit
+0x440 Wow64SplitPages : Pos 4, 1 Bit
+0x440 VmDeleted : Pos 5, 1 Bit
+0x440 OutswapEnabled : Pos 6, 1 Bit
+0x440 Outswapped : Pos 7, 1 Bit
+0x440 ForkFailed : Pos 8, 1 Bit
+0x440 Wow64VaSpace4Gb : Pos 9, 1 Bit
+0x440 AddressSpaceInitialized : Pos 10, 2 Bits
+0x440 SetTimerResolution : Pos 12, 1 Bit
+0x440 BreakOnTermination : Pos 13, 1 Bit
+0x440 DeprioritizeViews : Pos 14, 1 Bit
+0x440 WriteWatch : Pos 15, 1 Bit
+0x440 ProcessInSession : Pos 16, 1 Bit
+0x440 OverrideAddressSpace : Pos 17, 1 Bit
+0x440 HasAddressSpace : Pos 18, 1 Bit
+0x440 LaunchPrefetched : Pos 19, 1 Bit
+0x440 InjectInpageErrors : Pos 20, 1 Bit
+0x440 VmTopDown : Pos 21, 1 Bit
+0x440 ImageNotifyDone : Pos 22, 1 Bit
+0x440 PdeUpdateNeeded : Pos 23, 1 Bit
+0x440 VdmAllowed : Pos 24, 1 Bit
+0x440 CrossSessionCreate : Pos 25, 1 Bit
+0x440 ProcessInserted : Pos 26, 1 Bit
+0x440 DefaultIoPriority : Pos 27, 3 Bits
+0x440 ProcessSelfDelete : Pos 30, 1 Bit
+0x440 SetTimerResolutionLink : Pos 31, 1 Bit
+0x444 ExitStatus : Int4B
+0x448 VadRoot : _MM_AVL_TABLE
+0x488 AlpcContext : _ALPC_PROCESS_CONTEXT
+0x4a8 TimerResolutionLink : _LIST_ENTRY
+0x4b8 RequestedTimerResolution : Uint4B
+0x4bc ActiveThreadsHighWatermark : Uint4B
+0x4c0 SmallestTimerResolution : Uint4B
+0x4c8 TimerResolutionStackRecord : Ptr64 _PO_DIAG_STACK_RECORD 复制代码
可以看到在x64中EPROCESS在0x338出的偏移(offset)是成员Peb(64位_PEB结构体指针),利用指针的偏移量即可获得PEB结构体指针的地址;
同样看一下在PEB结构体中:
kd> dt _PEB
nt!_PEB
+0x000 InheritedAddressSpace : UChar
+0x001 ReadImageFileExecOptions : UChar
+0x002 BeingDebugged : UChar
+0x003 BitField : UChar
+0x003 ImageUsesLargePages : Pos 0, 1 Bit
+0x003 IsProtectedProcess : Pos 1, 1 Bit
+0x003 IsLegacyProcess : Pos 2, 1 Bit
+0x003 IsImageDynamicallyRelocated : Pos 3, 1 Bit
+0x003 SkipPatchingUser32Forwarders : Pos 4, 1 Bit
+0x003 SpareBits : Pos 5, 3 Bits
+0x008 Mutant : Ptr64 Void
+0x010 ImageBaseAddress : Ptr64 Void
+0x018 Ldr : Ptr64 _PEB_LDR_DATA
+0x020 ProcessParameters : Ptr64 _RTL_USER_PROCESS_PARAMETERS
+0x028 SubSystemData : Ptr64 Void
+0x030 ProcessHeap : Ptr64 Void
+0x038 FastPebLock : Ptr64 _RTL_CRITICAL_SECTION
+0x040 AtlThunkSListPtr : Ptr64 Void
+0x048 IFEOKey : Ptr64 Void
+0x050 CrossProcessFlags : Uint4B
+0x050 ProcessInJob : Pos 0, 1 Bit
+0x050 ProcessInitializing : Pos 1, 1 Bit
+0x050 ProcessUsingVEH : Pos 2, 1 Bit
+0x050 ProcessUsingVCH : Pos 3, 1 Bit
+0x050 ProcessUsingFTH : Pos 4, 1 Bit
+0x050 ReservedBits0 : Pos 5, 27 Bits
+0x058 KernelCallbackTable : Ptr64 Void
+0x058 UserSharedInfoPtr : Ptr64 Void
+0x060 SystemReserved : [1] Uint4B
+0x064 AtlThunkSListPtr32 : Uint4B
+0x068 ApiSetMap : Ptr64 Void
+0x070 TlsExpansionCounter : Uint4B
+0x078 TlsBitmap : Ptr64 Void
+0x080 TlsBitmapBits : [2] Uint4B
+0x088 ReadOnlySharedMemoryBase : Ptr64 Void
+0x090 HotpatchInformation : Ptr64 Void
+0x098 ReadOnlyStaticServerData : Ptr64 Ptr64 Void
+0x0a0 AnsiCodePageData : Ptr64 Void
+0x0a8 OemCodePageData : Ptr64 Void
+0x0b0 UnicodeCaseTableData : Ptr64 Void
+0x0b8 NumberOfProcessors : Uint4B
+0x0bc NtGlobalFlag : Uint4B
+0x0c0 CriticalSectionTimeout : _LARGE_INTEGER
+0x0c8 HeapSegmentReserve : Uint8B
+0x0d0 HeapSegmentCommit : Uint8B
+0x0d8 HeapDeCommitTotalFreeThreshold : Uint8B
+0x0e0 HeapDeCommitFreeBlockThreshold : Uint8B
+0x0e8 NumberOfHeaps : Uint4B
+0x0ec MaximumNumberOfHeaps : Uint4B
+0x0f0 ProcessHeaps : Ptr64 Ptr64 Void
+0x0f8 GdiSharedHandleTable : Ptr64 Void
+0x100 ProcessStarterHelper : Ptr64 Void
+0x108 GdiDCAttributeList : Uint4B
+0x110 LoaderLock : Ptr64 _RTL_CRITICAL_SECTION
+0x118 OSMajorVersion : Uint4B
+0x11c OSMinorVersion : Uint4B
+0x120 OSBuildNumber : Uint2B
+0x122 OSCSDVersion : Uint2B
+0x124 OSPlatformId : Uint4B
+0x128 ImageSubsystem : Uint4B
+0x12c ImageSubsystemMajorVersion : Uint4B
+0x130 ImageSubsystemMinorVersion : Uint4B
+0x138 ActiveProcessAffinityMask : Uint8B
+0x140 GdiHandleBuffer : [60] Uint4B
+0x230 PostProcessInitRoutine : Ptr64 void
+0x238 TlsExpansionBitmap : Ptr64 Void
+0x240 TlsExpansionBitmapBits : [32] Uint4B
+0x2c0 SessionId : Uint4B
+0x2c8 AppCompatFlags : _ULARGE_INTEGER
+0x2d0 AppCompatFlagsUser : _ULARGE_INTEGER
+0x2d8 pShimData : Ptr64 Void
+0x2e0 AppCompatInfo : Ptr64 Void
+0x2e8 CSDVersion : _UNICODE_STRING
+0x2f8 ActivationContextData : Ptr64 _ACTIVATION_CONTEXT_DATA
+0x300 ProcessAssemblyStorageMap : Ptr64 _ASSEMBLY_STORAGE_MAP
+0x308 SystemDefaultActivationContextData : Ptr64 _ACTIVATION_CONTEXT_DATA
+0x310 SystemAssemblyStorageMap : Ptr64 _ASSEMBLY_STORAGE_MAP
+0x318 MinimumStackCommit : Uint8B
+0x320 FlsCallback : Ptr64 _FLS_CALLBACK_INFO
+0x328 FlsListHead : _LIST_ENTRY
+0x338 FlsBitmap : Ptr64 Void
+0x340 FlsBitmapBits : [4] Uint4B
+0x350 FlsHighIndex : Uint4B
+0x358 WerRegistrationData : Ptr64 Void
+0x360 WerShipAssertPtr : Ptr64 Void
+0x368 pContextData : Ptr64 Void
+0x370 pImageHeaderHash : Ptr64 Void
+0x378 TracingFlags : Uint4B
+0x378 HeapTracingEnabled : Pos 0, 1 Bit
+0x378 CritSecTracingEnabled : Pos 1, 1 Bit
+0x378 SpareTracingBits : Pos 2, 30 Bits 复制代码
可以看出,PEB结构体地址在0x018处偏移是指向了Ldr(_PEB_LDR_DATA结构体的64位指针),同样利用指针的偏移可以得到它,进一步看看_PEB_LDR_DATA这个结构图中有什么:
_PEB_LDR_DATA:
kd> dt _PEB_LDR_DATA
nt!_PEB_LDR_DATA
+0x000 Length : Uint4B
+0x004 Initialized : UChar
+0x008 SsHandle : Ptr64 Void
+0x010 InLoadOrderModuleList : _LIST_ENTRY
+0x020 InMemoryOrderModuleList : _LIST_ENTRY
+0x030 InInitializationOrderModuleList : _LIST_ENTRY
+0x040 EntryInProgress : Ptr64 Void
+0x048 ShutdownInProgress : UChar
+0x050 ShutdownThreadId : Ptr64 Void 复制代码
PEB_LDR_DATA中,在0x010偏移处可以得到InLoadOrderModuleList这个链表,是双向链表_LIST_ENTRY类型的,我们最后遍历这个LIST_ENTRY链表就可以了。
以下为代码实现,先说一下几个注意事项:
1.程序中需要利用PsLookupProcessByProcessId来获取制定进程的PERPROCESS,然后进行指针的偏移量计算来获得PEB, LDR以及最后的双向链表InLoadOrderModuleList,
其中比如我们第一次得到了PEPROCESS,将其转化为ULONG64类型的数,所做的(ULONG64)eproc + 0x338得到的是PEB结构体指针的地址,
所以我们如果要得到PEB结构体的指针(也就是说PEB结构体的地址)的话,需要再用“*”来取他的值,也就是这样:ULONG64 peb_addr = *(PULONG64)((ULONG64)eproc + 0x338);同理获得ldr结构体的地址也需要注意!
2.获取PEB结构体的地址可以使用API:PsGetProcessPeb,但是为了锻炼C语言指针的应用能力,本程序全部使用结构体指针的偏移来获取。
3.本程序用枚举当前虚拟机Win7 x64上的explorer.exe的模块为例,如果重复使用的话需要重新更新一下所要枚举的进程的当前句柄。
程序如下(C语言):
#include <ntddk.h>
#include <windef.h>
#define PEB_OFFSET_IN_EPROCESS 0x338
#define LDR_OFFSET_IN_PEB 0x018
#define InLoadOrderModuleList_OFFSET 0x010
typedef struct _LDR_DATA_TABLE_ENTRY
{
LIST_ENTRY64 InLoadOrderLinks;
LIST_ENTRY64 InMemoryOrderLinks;
LIST_ENTRY64 InInitializationOrderLinks;
PVOID DllBase;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
ULONG Flags;
USHORT LoadCount;
USHORT TlsIndex;
PVOID SectionPointer;
ULONG CheckSum;
PVOID LoadedImports;
PVOID EntryPointActivationContext;
PVOID PatchInformation;
LIST_ENTRY64 ForwarderLinks;
LIST_ENTRY64 ServiceTagLinks;
LIST_ENTRY64 StaticLinks;
PVOID ContextInformation;
ULONG64 OriginalBase;
LARGE_INTEGER LoadTime;
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
typedef struct _KAPC_STATE
{
LIST_ENTRY ApcListHead[2];
PKPROCESS Process;
UCHAR KernelApcInProgress;
UCHAR KernelApcPending;
UCHAR UserApcPending;
} KAPC_STATE, *PKAPC_STATE;
// Functions declaration
NTKERNELAPI NTSTATUS PsLookupProcessByProcessId(HANDLE ProcessId, PEPROCESS *Process);
VOID KeStackAttachProcess(PRKPROCESS PROCESS,PKAPC_STATE ApcState);
VOID KeUnstackDetachProcess(PKAPC_STATE ApcState);
//
// Get the pointer to the EPROCESS of the specific pid on the process.
//
PEPROCESS LookupProcess(HANDLE hPid)
{
PEPROCESS eproc = NULL;
if (NT_SUCCESS(PsLookupProcessByProcessId(hPid, &eproc)))
{
return eproc;
}
return NULL;
}
// Enumerate the module of the specific process.
VOID EnumerateModule(HANDLE hPid)
{
KAPC_STATE ks;
PEPROCESS eproc = LookupProcess(hPid);
if (eproc == NULL)
{
DbgPrint("Can't find the EPROCESS...\n");
return;
}
__try
{
// Get the peb address, the PEB structure in the EPROCESS is a pointer to PEB, named PPEB.
// So the "(ULONG64)eproc + PEB_OFFSET_IN_EPROCESS" is the address the pointer to PEB.
// And finally, use the "*" to get the address to the PEB structure.
ULONG64 peb = *(PULONG64)((ULONG64)eproc + PEB_OFFSET_IN_EPROCESS);
KeStackAttachProcess(eproc, &ks);
// The LDR structure in PEB is also a pointer to PEB_LDR_DATA
// So, "(ULONG64)peb + LDR_OFFSET_IN_PEB" is the address of pointer to PEB_LDR_DATA.
// And the ULONG64 ldr is finally get the address of PEB_LDR_DATA structure.
ULONG64 ldr = *(PULONG64)((ULONG64)peb + LDR_OFFSET_IN_PEB);
// Get the address of "InLoadOrderModuleList" which in the PEB_LDR_DATA structure.
PLIST_ENTRY pListHead = (PLIST_ENTRY)(ldr + InLoadOrderModuleList_OFFSET);
PLIST_ENTRY pMod = pListHead->Flink;
while (pMod != pListHead)
{
DbgPrint("Base=%p, Size=%ld, Path=%wZ\n",
(PVOID)(((PLDR_DATA_TABLE_ENTRY)pMod)->DllBase),
(ULONG)(((PLDR_DATA_TABLE_ENTRY)pMod)->SizeOfImage),
&(((PLDR_DATA_TABLE_ENTRY)pMod)->FullDllName));
pMod = pMod->Flink;
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
DbgPrint("EXCEPTION_EXECUTE_HANDLER is occure...\n");
}
KeUnstackDetachProcess(&ks);
}
VOID DriverUnload(IN PDRIVER_OBJECT pDrvObj)
{
DbgPrint("DriverUnload...\n");
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDrvObj, IN PUNICODE_STRING RegistryPath)
{
DbgPrint("DriverEntry...\n");
pDrvObj->DriverUnload = DriverUnload;
EnumerateModule((HANDLE)1320); // explorer.exe's current handle pid.
return STATUS_SUCCESS;
} 复制代码
运行结果(只显示一部分结果了哈):
本贴用作学习笔记用于记录遇到的错误和解决方法,便于大家交流讨论和之后的温习。
有关PEB,LDR的只是可以参考一下站里的帖子:
https://www.0xaa55.com/forum.php ... 5&highlight=LDR
https://www.0xaa55.com/forum.php ... 3&highlight=PEB