Windows Process内存组织结构及重要域解析
最近恶补操作系统和一些底层的知识。遂写篇文章来说说从操作系统的角度来研究Process的一些结构,实现,Porcess的初始化,重要的结构体域的定义,代表的含义,如何组织起来的,等。还有在前段时间研究托管的static字段到底在内存中如何组织的时候,遇到的handle table不熟悉的问题。
一个xp里面的Process,是由几个Eprocess,执行体进程块来表示的。这个Eprocess里面不仅包含了进程相关的一些重要的数据结构,同时还包含了进程一些重要的环境变量之内的东西。EPROCESS块位于操作系统的进程空间里面。不过PEB块是在用户空间里面的。因为PEB块包含了一些需要用户来修改的数据,放在操作系统空间中会导致不安全和频繁的操作模式的切换。
从网上c了一个图过来说明,这个图是windows internal第六章里面的。一个完整的Process的东西分别放在了SYSTEM ADDRESS和PROCESS ADDRESS里面。用来适应不同的操作模式。
在内核调试模式下,可以dt出Process的内核执行块的结构:
lkd> dt nt!_eprocess
+0x000 Pcb : _KPROCESS
+0x06c ProcessLock : _EX_PUSH_LOCK
+0x070 CreateTime : _LARGE_INTEGER
+0x078 ExitTime : _LARGE_INTEGER
+0x080 RundownProtect : _EX_RUNDOWN_REF
+0x084 UniqueProcessId : Ptr32 Void
+0x088 ActiveProcessLinks : _LIST_ENTRY
+0x090 QuotaUsage : [3] Uint4B
+0x09c QuotaPeak : [3] Uint4B
+0x0a8 CommitCharge : Uint4B
+0x0ac PeakVirtualSize : Uint4B
+0x0b0 VirtualSize : Uint4B
+0x0b4 SessionProcessLinks : _LIST_ENTRY
+0x0bc DebugPort : Ptr32 Void
+0x0c0 ExceptionPort : Ptr32 Void
+0x0c4 ObjectTable : Ptr32 _HANDLE_TABLE
+0x0c8 Token : _EX_FAST_REF
+0x0cc WorkingSetLock : _FAST_MUTEX
+0x0ec WorkingSetPage : Uint4B
+0x0f0 AddressCreationLock : _FAST_MUTEX
+0x110 HyperSpaceLock : Uint4B
+0x114 ForkInProgress : Ptr32 _ETHREAD
+0x118 HardwareTrigger : Uint4B
+0x11c VadRoot : Ptr32 Void
+0x120 VadHint : Ptr32 Void
+0x124 CloneRoot : Ptr32 Void
+0x128 NumberOfPrivatePages : Uint4B
+0x12c NumberOfLockedPages : Uint4B
+0x130 Win32Process : Ptr32 Void
+0x134 Job : Ptr32 _EJOB
+0x138 SectionObject : Ptr32 Void
+0x13c SectionBaseAddress : Ptr32 Void
+0x140 QuotaBlock : Ptr32 _EPROCESS_QUOTA_BLOCK
+0x144 WorkingSetWatch : Ptr32 _PAGEFAULT_HISTORY
+0x148 Win32WindowStation : Ptr32 Void
+0x14c InheritedFromUniqueProcessId : Ptr32 Void
+0x150 LdtInformation : Ptr32 Void
+0x154 VadFreeHint : Ptr32 Void
+0x158 VdmObjects : Ptr32 Void
+0x15c DeviceMap : Ptr32 Void
+0x160 PhysicalVadList : _LIST_ENTRY
+0x168 PageDirectoryPte : _HARDWARE_PTE
+0x168 Filler : Uint8B
+0x170 Session : Ptr32 Void
+0x174 ImageFileName : [16] UChar
+0x184 JobLinks : _LIST_ENTRY
+0x18c LockedPagesList : Ptr32 Void
+0x190 ThreadListHead : _LIST_ENTRY
+0x198 SecurityPort : Ptr32 Void
+0x19c PaeTop : Ptr32 Void
+0x1a0 ActiveThreads : Uint4B
+0x1a4 GrantedAccess : Uint4B
+0x1a8 DefaultHardErrorProcessing : Uint4B
+0x1ac LastThreadExitStatus : Int4B
+0x1b0 Peb : Ptr32 _PEB
+0x1b4 PrefetchTrace : _EX_FAST_REF
+0x1b8 ReadOperationCount : _LARGE_INTEGER
+0x1c0 WriteOperationCount : _LARGE_INTEGER
+0x1c8 OtherOperationCount : _LARGE_INTEGER
+0x1d0 ReadTransferCount : _LARGE_INTEGER
+0x1d8 WriteTransferCount : _LARGE_INTEGER
+0x1e0 OtherTransferCount : _LARGE_INTEGER
+0x1e8 CommitChargeLimit : Uint4B
+0x1ec CommitChargePeak : Uint4B
+0x1f0 AweInfo : Ptr32 Void
+0x1f4 SeAuditProcessCreationInfo : _SE_AUDIT_PROCESS_CREATION_INFO
+0x1f8 Vm : _MMSUPPORT
+0x238 LastFaultCount : Uint4B
+0x23c ModifiedPageCount : Uint4B
+0x240 NumberOfVads : Uint4B
+0x244 JobStatus : Uint4B
+0x248 Flags : Uint4B
+0x248 CreateReported : Pos 0, 1 Bit
+0x248 NoDebugInherit : Pos 1, 1 Bit
+0x248 ProcessExiting : Pos 2, 1 Bit
+0x248 ProcessDelete : Pos 3, 1 Bit
+0x248 Wow64SplitPages : Pos 4, 1 Bit
+0x248 VmDeleted : Pos 5, 1 Bit
+0x248 OutswapEnabled : Pos 6, 1 Bit
+0x248 Outswapped : Pos 7, 1 Bit
+0x248 ForkFailed : Pos 8, 1 Bit
+0x248 HasPhysicalVad : Pos 9, 1 Bit
+0x248 AddressSpaceInitialized : Pos 10, 2 Bits
+0x248 SetTimerResolution : Pos 12, 1 Bit
+0x248 BreakOnTermination : Pos 13, 1 Bit
+0x248 SessionCreationUnderway : Pos 14, 1 Bit
+0x248 WriteWatch : Pos 15, 1 Bit
+0x248 ProcessInSession : Pos 16, 1 Bit
+0x248 OverrideAddressSpace : Pos 17, 1 Bit
+0x248 HasAddressSpace : Pos 18, 1 Bit
+0x248 LaunchPrefetched : Pos 19, 1 Bit
+0x248 InjectInpageErrors : Pos 20, 1 Bit
+0x248 VmTopDown : Pos 21, 1 Bit
+0x248 Unused3 : Pos 22, 1 Bit
+0x248 Unused4 : Pos 23, 1 Bit
+0x248 VdmAllowed : Pos 24, 1 Bit
+0x248 Unused : Pos 25, 5 Bits
+0x248 Unused1 : Pos 30, 1 Bit
+0x248 Unused2 : Pos 31, 1 Bit
+0x24c ExitStatus : Int4B
+0x250 NextPageColor : Uint2B
+0x252 SubSystemMinorVersion : UChar
+0x253 SubSystemMajorVersion : UChar
+0x252 SubSystemVersion : Uint2B
+0x254 PriorityClass : UChar
+0x255 WorkingSetAcquiredUnsafe : UChar
+0x258 Cookie : Uint4B
也可以用dt nt!_Kprocess –r1命令来展开成为一级的形式,在输出中显示结构体的定义。
首先看看_LIST_ENTRY表示的几个域:
+0x160 PhysicalVadList : _LIST_ENTRY
+0x184 JobLinks : _LIST_ENTRY
+0x190 ThreadListHead : _LIST_ENTRY
+0x0b4 SessionProcessLinks : _LIST_ENTRY
+0x088 ActiveProcessLinks : _LIST_ENTRY
首先给看看_LIST_ENTRY的定义:
typedef struct _LIST_ENTRY {
struct _LIST_ENTRY *Flink;
struct _LIST_ENTRY *Blink;
} LIST_ENTRY, *PLIST_ENTRY, *RESTRICTED_POINTER PRLIST_ENTRY;
使用这个结构体,就可以把许多同类型的数据组成一个链表。譬如有一种隐藏进程的方法,就是通过截断EPROCESS的ActiveProcessLinks链表来隐藏进程。
具体的做法,就是通过PsGetCurrentProcess函数,来获取当前的KPROCESS的地址,而KPROCESS就是进程执行体,就是上面的EPROCESS的第一项。然后根据不同的操作系统的版本的偏移位置的不同,来得到_LIST_ENTRY链表,然后通过修改链表来达到隐藏进程的目的。
同时,根据PsGetCurrentProcess返回的KPROCESS的地址得到了EPROCESS执行体之后,具体分析不同版本操作系统的EPROCESS结构体的不同,还可以做很多事情。
从给起的变量的名字上面,可以大致的知道这些链表都把啥东西链接了起来。
整个EPROCESS的大小和包含的结构体的定义,可以使用!strct _EPROCESS这个命令来获取到:
lkd> !strct _eprocess
struct _EPROCESS (sizeof=648)
+000 struct _KPROCESS Pcb
+070 struct _KEVENT LockEvent
+090 union _LARGE_INTEGER ExitTime
+098 struct _KTHREAD *LockOwner
+0a0 struct _LIST_ENTRY ActiveProcessLinks
+0d0 struct _MMSUPPORT Vm
+118 struct _LIST_ENTRY SessionProcessLinks
+128 struct _HANDLE_TABLE *ObjectTable
+130 struct _FAST_MUTEX WorkingSetLock
+158 struct _FAST_MUTEX AddressCreationLock
+17c struct _ETHREAD *ForkInProgress
+184 struct _KEVENT *VmOperationEvent
+1b0 struct _PEB *Peb
+1b8 struct _EPROCESS_QUOTA_BLOCK *QuotaBlock
+1c0 struct _PAGEFAULT_HISTORY *WorkingSetWatch
+1e8 struct _LIST_ENTRY PhysicalVadList
+1f0 struct _HARDWARE_PTE_X86 PageDirectoryPte
+218 struct _EJOB *Job
+220 struct _LIST_ENTRY JobLinks
+230 struct _WOW64_PROCESS *Wow64Process
+238 union _LARGE_INTEGER ReadOperationCount
+240 union _LARGE_INTEGER WriteOperationCount
+248 union _LARGE_INTEGER OtherOperationCount
+250 union _LARGE_INTEGER ReadTransferCount
+258 union _LARGE_INTEGER WriteTransferCount
+260 union _LARGE_INTEGER OtherTransferCount
+270 struct _LIST_ENTRY ThreadListHead
+278 struct _RTL_BITMAP *VadPhysicalPagesBitMap
这里只留下struct和union,区域的数据类型全部去掉了。
每个EPROCESS的第一个域,都是一个KPROCESS域。KPROCESS包含了公共的分发器对象头,指向进程页面目录的指针,KTHREAD的内核线程块的列表,线程的内核时间和用户时间等等。简单的瞅瞅:
lkd> dt _KPROCESS
ntdll!_KPROCESS
+0x000 Header : _DISPATCHER_HEADER
+0x010 ProfileListHead : _LIST_ENTRY
//进程的页目录
+0x018 DirectoryTableBase : [2] Uint4B
+0x020 LdtDescriptor : _KGDTENTRY
//GDT的入口
+0x028 Int21Descriptor : _KIDTENTRY
//IDT的入口
+0x030 IopmOffset : Uint2B
+0x032 Iopl : UChar
+0x033 Unused : UChar
+0x034 ActiveProcessors : Uint4B
+0x038 KernelTime : Uint4B
+0x03c UserTime : Uint4B
+0x040 ReadyListHead : _LIST_ENTRY
+0x048 SwapListEntry : _SINGLE_LIST_ENTRY
+0x04c VdmTrapcHandler : Ptr32 Void
+0x050 ThreadListHead : _LIST_ENTRY
//KTHREAD的链
+0x058 ProcessLock : Uint4B
+0x05c Affinity : Uint4B
+0x060 StackCount : Uint2B
+0x062 BasePriority : Char
+0x063 ThreadQuantum : Char
+0x064 AutoAlignment : UChar
+0x065 State : UChar
+0x066 ThreadSeed : UChar
+0x067 DisableBoost : UChar
+0x068 PowerState : UChar
+0x069 DisableQuantum : UChar
+0x06a IdealNode : UChar
+0x06b Flags : _KEXECUTE_OPTIONS
//运行的标识位
+0x06b ExecuteOptions : Uchar
可以用!process 0 0来获取系统里面正在运行的所有线程的EPROCESS的地址:
lkd> !process 0 0
PROCESS 821b77c0 SessionId: none Cid: 0004 Peb: 00000000 ParentCid: 0000
DirBase: 02ac0020 ObjectTable: e1001e10 HandleCount: 277.
Image: System
PROCESS 8207c740 SessionId: none Cid: 0180 Peb: 7ffd5000 ParentCid: 0004
DirBase: 02ac0040 ObjectTable: e13ad948 HandleCount: 21.
Image: SMSS.EXE
PROCESS 820ee020 SessionId: 0 Cid: 027c Peb: 7ffdf000 ParentCid: 0180
DirBase: 02ac0060 ObjectTable: e1401eb0 HandleCount: 309.
Image: CSRSS.EXE
如果不带参数的话,就直接获取当前正在运行的进程的情况:
lkd> !process
PROCESS 81fe15c8 SessionId: 0 Cid: 0604 Peb: 7ffd4000 ParentCid: 05c4
DirBase: 02ac0320 ObjectTable: e1ae43e8 HandleCount: 635.
Image: windbg.exe
VadRoot 81dc61b0 Vads 792 Clone 0 Private 43397. Modified 74582. Locked 1.
DeviceMap e1a2c530
Token e2343bd0
ElapsedTime 3 Days 00:51:45.656
UserTime 00:02:52.656
KernelTime 00:01:08.937
QuotaPoolUsage[PagedPool] 140124
QuotaPoolUsage[NonPagedPool] 32200
Working Set Sizes (now,min,max) (35983, 50, 345) (143932KB, 200KB, 1380KB)
PeakWorkingSetSize 45310
VirtualSize 293 Mb
PeakVirtualSize 424 Mb
PageFaultCount 210305
MemoryPriority BACKGROUND
BasePriority 8
CommitCharge 44348
THREAD 81da02e8 Cid 0604.04fc Teb: 7ffdf000 Win32Thread: e2329eb0 WAIT: (WrUserRequest) UserMode Non-Alertable
82133d30 SynchronizationEvent
略去几条线程的信息。
对比KPROCESS的结构和上面Process命令得到的输出结果,可以看到,Process命令只是输出了一部分的Process的信息。如果采用!Process 0 0来获取到某特特定进程的Eprocess的地址做为Process命令的参数,就可以得到特定的Process的信息。
同理,对PEB的查看也是一样:
lkd> !strct peb
struct _PEB (sizeof=488)
+000 byte InheritedAddressSpace
+001 byte ReadImageFileExecOptions
+002 byte BeingDebugged
+003 byte SpareBool
+004 void *Mutant
+008 void *ImageBaseAddress
+00c struct _PEB_LDR_DATA *Ldr
+010 struct _RTL_USER_PROCESS_PARAMETERS *ProcessParameters
+014 void *SubSystemData
+018 void *ProcessHeap
+01c void *FastPebLock
+020 void *FastPebLockRoutine
+024 void *FastPebUnlockRoutine
+028 uint32 EnvironmentUpdateCount
+02c void *KernelCallbackTable
+030 uint32 SystemReserved[2]
+038 struct _PEB_FREE_BLOCK *FreeList
+03c uint32 TlsExpansionCounter
+040 void *TlsBitmap
+044 uint32 TlsBitmapBits[2]
+04c void *ReadOnlySharedMemoryBase
+050 void *ReadOnlySharedMemoryHeap
+054 void **ReadOnlyStaticServerData
+058 void *AnsiCodePageData
+05c void *OemCodePageData
+060 void *UnicodeCaseTableData
+064 uint32 NumberOfProcessors
+068 uint32 NtGlobalFlag
+070 union _LARGE_INTEGER CriticalSectionTimeout
+070 uint32 LowPart
+074 int32 HighPart
+070 struct __unnamed3 u
+070 uint32 LowPart
+074 int32 HighPart
+070 int64 QuadPart
+078 uint32 HeapSegmentReserve
+07c uint32 HeapSegmentCommit
+080 uint32 HeapDeCommitTotalFreeThreshold
+084 uint32 HeapDeCommitFreeBlockThreshold
+088 uint32 NumberOfHeaps
+08c uint32 MaximumNumberOfHeaps
+090 void **ProcessHeaps
+094 void *GdiSharedHandleTable
+098 void *ProcessStarterHelper
+09c uint32 GdiDCAttributeList
+0a0 void *LoaderLock
+0a4 uint32 OSMajorVersion
+0a8 uint32 OSMinorVersion
+0ac uint16 OSBuildNumber
+0ae uint16 OSCSDVersion
+0b0 uint32 OSPlatformId
+0b4 uint32 ImageSubsystem
+0b8 uint32 ImageSubsystemMajorVersion
+0bc uint32 ImageSubsystemMinorVersion
+0c0 uint32 ImageProcessAffinityMask
+0c4 uint32 GdiHandleBuffer[34]
+14c function *PostProcessInitRoutine
+150 void *TlsExpansionBitmap
+154 uint32 TlsExpansionBitmapBits[32]
+1d4 uint32 SessionId
+1d8 void *AppCompatInfo
+1dc struct _UNICODE_STRING CSDVersion
+1dc uint16 Length
+1de uint16 MaximumLength
+1e0 uint16 *Buffer
本来还准备说说handle table,上面的废话太多了,下篇再说了。
7/22/2008 2:35:05 PM 首发sscli.cnblogs.com lbq1221119@jl
posted on 2008-07-22 14:45 lbq1221119 阅读(4394) 评论(11) 编辑 收藏 举报