欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【内核原理与实现 006】EPROCESS 结构体属性介绍

程序员文章站 2022-07-13 10:52:24
...
typedef struct _EPROCESS {
    // KPROCESS 和 EPROCESS 地址相同
    KPROCESS Pcb;

    //
    // Lock used to protect:
    // The list of threads in the process.
    // Process token.
    // Win32 process field.
    // Process and thread affinity setting.
    //

    // 推锁对象,用于保护 EPROCESS 的数据成员
    EX_PUSH_LOCK ProcessLock;

    // 进程的创建和退出时间
    LARGE_INTEGER CreateTime;
    LARGE_INTEGER ExitTime;

    //
    // Structure to allow lock free cross process access to the process
    // handle table, process section and address space. Acquire rundown
    // protection with this if you do cross process handle table, process
    // section or address space references.
    //

    // 进程的停止保护锁,进程销毁时,要等到所有其他进程和线程已经释放此锁,才能继续进行
    EX_RUNDOWN_REF RundownProtect;

    // 进程唯一编号,进程创建时指定
    HANDLE UniqueProcessId;

    //
    // Global list of all processes in the system. Processes are removed
    // from this list in the object deletion routine.  References to
    // processes in this list must be done with ObReferenceObjectSafe
    // because of this.
    //

    // 所有进程都挂入了全局链表 PsActiveProcessHead 中,ActiveProcessLinks 就是
    // 当前进程的挂入点。可通过此成员遍历所有进程。
    LIST_ENTRY ActiveProcessLinks;

    //
    // Quota Fields.
    //

    // 下面两个数组的长度均为3,分别对应非换页内存池,换页内存池和交换文件中的内存使用情况。
    // 这两个数组是在 PspChargeQuota 函数内计算的。
    
    // 进程内存使用量
    SIZE_T QuotaUsage[PsQuotaTypes];
    
    // 进程内存使用量峰值
    SIZE_T QuotaPeak[PsQuotaTypes];
    
    // 进程的虚拟内存已提交的页面数量
    SIZE_T CommitCharge;

    //
    // VmCounters.
    //

    // 进程虚拟内存大小峰值
    SIZE_T PeakVirtualSize;
    
    // 进程虚拟内存大小
    SIZE_T VirtualSize;

    // 当进程加入到一个系统会话中时,通过 SessionProcessLinks 挂入该会话的进程链表中
    LIST_ENTRY SessionProcessLinks;

    
    // 当进程中的线程发生用户模式异常时,内核的异常处理例程在异常处理过程中,将向该进程的异常
    // 端口或调试端口发送消息,从而使这些端口的接收方(调试器或windows子系统)能够处理该异常。
    // 5.2.7节将介绍异常分发过程。
    
    // 调试端口
    PVOID DebugPort;
    
    // 异常端口
    PVOID ExceptionPort;
    
    // 句柄表,存储了所有被该进程打开的内核对象的句柄
    PHANDLE_TABLE ObjectTable;

    //
    // Security.
    //

    // 指向该进程的访问令牌,用于该进程的安全访问检查
    EX_FAST_REF Token;

    // 工作集页面
    PFN_NUMBER WorkingSetPage;
    
    // 守护互斥体锁(guarded mutex),用于保护对地址空间的操作。
    // 当内核代码需要对虚拟地址空间进行操作时,必须在 AddressCreationLock 上执行锁操作,
    // 完成以后再解锁。LOCK_ADDRESS_SPACE 和 UNLOCK_ADDRESS_SPACE 宏用于简化代码。
    KGUARDED_MUTEX AddressCreationLock;
    
    // 自旋锁对象,用于保护进程的超空间
    KSPIN_LOCK HyperSpaceLock;

    // 指向正在复制地址空间的那个线程,仅当在地址空间复制的过程中,此值才有值,其他情况为 NULL
    // 详见 MiCloneProcessAddressSpace 函数
    struct _ETHREAD *ForkInProgress;
    
    
    ULONG_PTR HardwareTrigger;

    // 指向进程的物理VAD树根,并不总是存在,只有确实需要映射物理内存时才会被创建。
    PMM_AVL_TABLE PhysicalVadRoot;
    
    // 指向一个平衡树的根,当进程地址空间复制时创建此树,创建后直到进程退出时才销毁
    PVOID CloneRoot;
    
    // 私有页面数量
    PFN_NUMBER NumberOfPrivatePages;
    
    // 被锁住的页面数量
    PFN_NUMBER NumberOfLockedPages;
    
    // 指向由windows子系统管理的进程区域,如果此值不为 NULL,说明这是windows子系统进程(GUI进程)
    PVOID Win32Process;
    
    // 只有当进程属于Job(作业)时,才有值,本书不讨论 _EJOB
    struct _EJOB *Job;
    
    // 代表进程的内存区对象(进程的可执行映像文件的内存区对象)
    PVOID SectionObject;

    // 内存区对象基址
    PVOID SectionBaseAddress;

    // 进程的配额块,系统中的配额块相互串成一个双链表,每个配额块都可以被多个进程共享
    // 所以需要一个引用计数值用来说明当前有多少个进程正在使用这一配额块。
    // 配额块主要定义了非换页内存池、换页内存池和交换文件中的内存配额限制。
    // 系统默认配额块为 PspDefaultQuotaBlock ,存储所有配额块的链表是 PspQuotaBlockList
    PEPROCESS_QUOTA_BLOCK QuotaBlock;

    // 监视进程的页面错误,全局变量 PsWatchEnabled 控制页面错误监视功能的开关。如果开启,
    // 每次发生页面错误都会将错误记录到 WorkingSetWatch 域的 WatchInfo 成员数组中,
    // 直到数组满为止,详见 PsWatchWorkingSet 函数。
    PPAGEFAULT_HISTORY WorkingSetWatch;
    
    // 进程所属窗口站句柄
    HANDLE Win32WindowStation;
    
    // 父进程标识符,说明进程是从哪里继承来的
    HANDLE InheritedFromUniqueProcessId;

    // 用于维护一个进程的 LDT(局部描述符表)
    PVOID LdtInformation;
    
    // 指向一个提示 VAD(虚拟地址描述符) 节点,用于加速在VAD树种执行查找操作
    PVOID VadFreeHint;
    
    // 指向当前进程的 VDM 数据区,其类型为 VDM_PROCESS_OBJECTS
    // 进程可以通过 NtVdmControl 函数初始化 VDM
    PVOID VdmObjects;
    
    // 进程使用的设备表,通常情况下,同一个会话中的进程共享同样的设备表
    PVOID DeviceMap;

    PVOID Spare0[3]; // 保留
    
    union {
        // *页目录表的页表项
        HARDWARE_PTE PageDirectoryPte;
        
        ULONGLONG Filler;
    };
    
    // 指向进程所在的系统会话,实际上指向类型是 MM_SESSION_SPACE
    // 进程初始创建地址空间时会加入到当前的系统会话中。
    PVOID Session;
    
    // 进程映像文件名,不包含路径
    UCHAR ImageFileName[ 16 ];

    // 链表节点,存储了一个 Job 中所有进程的链表
    // 所有 Job 构成一个双链表 PspJobList ,每个 Job 中的进程又构成一个双链表。
    LIST_ENTRY JobLinks;
    
    // 指向 LOCK_HEADER 结构的指针,该结构包含一个链表头,通过此链表记录哪些页面被锁住。
    // base\ntos\mm\iosup.c 中有一组函数用于管理此链表,
    // 例如MiAddMdlTracker、MiFreeMdlTracker 和 MiUpdateMdlTracker 等
    PVOID LockedPagesList;

    // 包含了进程中的所有线程
    // KPROCESS-KTHREAD 和 EPROCESS-ETHREAD 都有各自的
    // ThreadListHead 和 ThreadListEntry ,实际上是同一个链表,不同的挂入点
    // 这是一个冗余设计,这体现了内核层和执行体层相对独立的关系。
    LIST_ENTRY ThreadListHead;

    //
    // Used by rdr/security for authentication.
    //

    // 安全端口,指向该进程与 lsass 进程(本地安全权威进程)之间的跨进程通信端口
    PVOID SecurityPort;

#ifdef _WIN64
    PWOW64_PROCESS Wow64Process;
#else
    // 用于支持 PAE 内存访问基址
    PVOID PaeTop;
#endif

    // 记录当前进程有多少个活动线程,此值为0时,所有的线程都将退出,于是进程也退出。
    ULONG ActiveThreads;

    // 包含了进程的访问权限,权限是一个位组合,各种权限定义详见 sdk\inc\ntpsapi.h 中
    // 的宏 PROCESS_<XXX> ,例如 PROCESS_VM_READ 表示虚拟内存读权限。
    ACCESS_MASK GrantedAccess;

    // 默认硬件错误处理,默认为1
    ULONG DefaultHardErrorProcessing;

    // 记录了刚才最后一个线程的退出状态
    NTSTATUS LastThreadExitStatus;

    //
    // Peb
    //

    // 指向3环PEB(进程环境块),包含了进程地址空间中的堆和系统模块等信息
    PPEB Peb;

    //
    // Pointer to the prefetches trace block.
    //
    
    // 快速引用,指向与该进程关联的一个预取痕迹结构,以支持该进程的预取,本书不讨论进程预取特性
    EX_FAST_REF PrefetchTrace;

    // 当前进程 NtReadFile 和 NtWriteFile 被调用的次数
    LARGE_INTEGER ReadOperationCount;
    LARGE_INTEGER WriteOperationCount;
    
    // 除读写以外的其他I/O操作次数
    LARGE_INTEGER OtherOperationCount;
    
    // I/O操作完成次数
    LARGE_INTEGER ReadTransferCount;
    LARGE_INTEGER WriteTransferCount;
    
    // 非读写操作完成次数
    LARGE_INTEGER OtherTransferCount;

    // 已提交页面数量的限制值,0表示无限制,WRK默认值是0
    SIZE_T CommitChargeLimit;
    
    // 尖峰时刻的已提交页面数量
    SIZE_T CommitChargePeak;

    // 指向 AWEINFO 结构的指针,作用是支持 AWE (Address Windowing Extension,地址窗口扩展)
    PVOID AweInfo;

    //
    // This is used for SeAuditProcessCreation.
    // It contains the full path to the image file.
    //

    // 创建进程时指定的进程映像全路径名,ImageFileName 实际上是从这里提取的
    SE_AUDIT_PROCESS_CREATION_INFO SeAuditProcessCreationInfo;

    // 进程管理虚拟内存的重要数据结构成员,第4章介绍工作集管理时会进一步介绍
    MMSUPPORT Vm;

#if !defined(_WIN64)
    
    // 所有拥有自己地址空间的进程都将加入到全局链表 MmProcessList 中,进程地址
    // 空间被销毁时,该节点脱离此链表。此链表可以使windows方便地执行一些全局的
    // 内存管理任务。
    LIST_ENTRY MmProcessLinks;
    
#else
    ULONG Spares[2];
#endif

    // 记录了该进程中已修改页面的数量
    ULONG ModifiedPageCount;

    #define PS_JOB_STATUS_NOT_REALLY_ACTIVE      0x00000001UL
    #define PS_JOB_STATUS_ACCOUNTING_FOLDED      0x00000002UL
    #define PS_JOB_STATUS_NEW_PROCESS_REPORTED   0x00000004UL
    #define PS_JOB_STATUS_EXIT_PROCESS_REPORTED  0x00000008UL
    #define PS_JOB_STATUS_REPORT_COMMIT_CHANGES  0x00000010UL
    #define PS_JOB_STATUS_LAST_REPORT_MEMORY     0x00000020UL
    #define PS_JOB_STATUS_REPORT_PHYSICAL_PAGE_CHANGES  0x00000040UL

    // 记录了进程所属 Job 的状态
    ULONG JobStatus;


    //
    // Process flags. Use interlocked operations with PS_SET_BITS, etc
    // to modify these.
    //

    #define PS_PROCESS_FLAGS_CREATE_REPORTED        0x00000001UL // Create process debug call has occurred
    #define PS_PROCESS_FLAGS_NO_DEBUG_INHERIT       0x00000002UL // Don't inherit debug port
    #define PS_PROCESS_FLAGS_PROCESS_EXITING        0x00000004UL // PspExitProcess entered
    #define PS_PROCESS_FLAGS_PROCESS_DELETE         0x00000008UL // Delete process has been issued
    #define PS_PROCESS_FLAGS_WOW64_SPLIT_PAGES      0x00000010UL // Wow64 split pages
    #define PS_PROCESS_FLAGS_VM_DELETED             0x00000020UL // VM is deleted
    #define PS_PROCESS_FLAGS_OUTSWAP_ENABLED        0x00000040UL // Outswap enabled
    #define PS_PROCESS_FLAGS_OUTSWAPPED             0x00000080UL // Outswapped
    #define PS_PROCESS_FLAGS_FORK_FAILED            0x00000100UL // Fork status
    #define PS_PROCESS_FLAGS_WOW64_4GB_VA_SPACE     0x00000200UL // Wow64 process with 4gb virtual address space
    #define PS_PROCESS_FLAGS_ADDRESS_SPACE1         0x00000400UL // Addr space state1
    #define PS_PROCESS_FLAGS_ADDRESS_SPACE2         0x00000800UL // Addr space state2
    #define PS_PROCESS_FLAGS_SET_TIMER_RESOLUTION   0x00001000UL // SetTimerResolution has been called
    #define PS_PROCESS_FLAGS_BREAK_ON_TERMINATION   0x00002000UL // Break on process termination
    #define PS_PROCESS_FLAGS_CREATING_SESSION       0x00004000UL // Process is creating a session
    #define PS_PROCESS_FLAGS_USING_WRITE_WATCH      0x00008000UL // Process is using the write watch APIs
    #define PS_PROCESS_FLAGS_IN_SESSION             0x00010000UL // Process is in a session
    #define PS_PROCESS_FLAGS_OVERRIDE_ADDRESS_SPACE 0x00020000UL // Process must use native address space (Win64 only)
    #define PS_PROCESS_FLAGS_HAS_ADDRESS_SPACE      0x00040000UL // This process has an address space
    #define PS_PROCESS_FLAGS_LAUNCH_PREFETCHED      0x00080000UL // Process launch was prefetched
    #define PS_PROCESS_INJECT_INPAGE_ERRORS         0x00100000UL // Process should be given inpage errors - hardcoded in trap.asm too
    #define PS_PROCESS_FLAGS_VM_TOP_DOWN            0x00200000UL // Process memory allocations default to top-down
    #define PS_PROCESS_FLAGS_IMAGE_NOTIFY_DONE      0x00400000UL // We have sent a message for this image
    #define PS_PROCESS_FLAGS_PDE_UPDATE_NEEDED      0x00800000UL // The system PDEs need updating for this process (NT32 only)
    #define PS_PROCESS_FLAGS_VDM_ALLOWED            0x01000000UL // Process allowed to invoke NTVDM support
    #define PS_PROCESS_FLAGS_SMAP_ALLOWED           0x02000000UL // Process allowed to invoke SMAP support
    #define PS_PROCESS_FLAGS_CREATE_FAILED          0x04000000UL // Process create failed

    #define PS_PROCESS_FLAGS_DEFAULT_IO_PRIORITY    0x38000000UL // The default I/O priority for created threads. (3 bits)

    #define PS_PROCESS_FLAGS_PRIORITY_SHIFT         27
    
    #define PS_PROCESS_FLAGS_EXECUTE_SPARE1         0x40000000UL //
    #define PS_PROCESS_FLAGS_EXECUTE_SPARE2         0x80000000UL //


    union {

        // 包含了进程的标志位,反映了进程当前状态和配置,上面那一大堆宏就是了
        ULONG Flags;

        //
        // Fields can only be set by the PS_SET_BITS and other interlocked
        // macros.  Reading fields is best done via the bit definitions so
        // references are easy to locate.
        //

        struct {
            ULONG CreateReported            : 1;
            ULONG NoDebugInherit            : 1;
            ULONG ProcessExiting            : 1;
            ULONG ProcessDelete             : 1;
            ULONG Wow64SplitPages           : 1;
            ULONG VmDeleted                 : 1;
            ULONG OutswapEnabled            : 1;
            ULONG Outswapped                : 1;
            ULONG ForkFailed                : 1;
            ULONG Wow64VaSpace4Gb           : 1;
            ULONG AddressSpaceInitialized   : 2;
            ULONG SetTimerResolution        : 1;
            ULONG BreakOnTermination        : 1;
            ULONG SessionCreationUnderway   : 1;
            ULONG WriteWatch                : 1;
            ULONG ProcessInSession          : 1;
            ULONG OverrideAddressSpace      : 1;
            ULONG HasAddressSpace           : 1;
            ULONG LaunchPrefetched          : 1;
            ULONG InjectInpageErrors        : 1;
            ULONG VmTopDown                 : 1;
            ULONG ImageNotifyDone           : 1;
            ULONG PdeUpdateNeeded           : 1;    // NT32 only
            ULONG VdmAllowed                : 1;
            ULONG SmapAllowed               : 1;
            ULONG CreateFailed              : 1;
            ULONG DefaultIoPriority         : 3;
            ULONG Spare1                    : 1;
            ULONG Spare2                    : 1;
        };
    };

    // 进程的退出状态,参见 public\sdk\inc\ntstatus.h
    NTSTATUS ExitStatus;

    // 用于物理页面分配算法
    USHORT NextPageColor;
    
    union {
        struct {
            // 下面两个值来源于进程映像文件的版本信息
            UCHAR SubSystemMinorVersion;	// 子系统次版本号
            UCHAR SubSystemMajorVersion;	// 子系统主版本号
        };
        USHORT SubSystemVersion;
    };
    
    // 进程优先级程度,在WRK 中包括以下类别:空闲类别(值为1)、普通类别(2)、
    // 高优先级类别(3)、实时类别(4)、普通之下类别(5)、普通之上类别(6),以及未知类别(0)
    UCHAR PriorityClass;

    // 指向一个平衡二叉树根,用于管理该进程的虚拟地址空间
    MM_AVL_TABLE VadRoot;

    // 代表该进程的随机值,第一次调用 NtQueryInformationProcess 函数获取 Cookie 值的
    // 时候,随机生成一个值,以后就用此值代表此进程。
    ULONG Cookie;

} EPROCESS, *PEPROCESS;