Windows NT系统浅析(修订版2)
phpskycn2013/01/24软件综合 IP:浙江
【前言】
本文将逐步粗略地介绍Windows NT系统的内部运行机理和细节,了解这些细节,有利于深入理解Windows NT系统涉及到各种功能的实现原理,方便相关的内核模块的开发。
本文适用于运行在IA32架构(包括IA32E提供的兼容模式)下的Windows NT系统,对于涉及内存管理的部分,会明确指出开启物理地址扩展(PAE)造成的变化情况。
通常情况下,本文的内容适用于下列Windows NT版本:
Windows NT 5.1(Windows XP 32位版)
Windows NT 5.2(Windows Server 2003)
对于更新的Windows NT 6.0/6.1/6.2基本适用,但微软在这些版本中增加或修改了部分机制。
对于较早的Windows NT 5.0版,大多数实现细节基本适用,但相关数据的值可能存在差异。
对于更早的Windows NT 4.0,本文描述的实现机理大部分适用,具体细节上差异可能比较多。

【适用对象】
本文并不是入门级的编程文章,主要介绍Windows NT系统的基本功能的原理和实现方法。读者至少需要具备较完备的C语言基础,能理解诸如查表这样的操作,并了解IA32架构(注:即所谓的X86架构)的基本硬件体系,对于Windows NT系统提供给程序员的各种编程接口(比如Windows API和一些已经文档化的内核函数)比较了解。
同样,本文并不会深入介绍NT系统中实现的具体细节,也不会过多地涉及系统本身的代码,对上述本文未涉及的内容有兴趣的读者,请参阅第六章中的相关学习资料。
通常情况下,本文适合下列类型的读者:
1.Windows应用开发人员
2.Windows内核/驱动程序开发人员
3.其它对Windows NT感兴趣的读者
一、基本结构
现代操作系统的基本任务是为应用程序提供抽象的接口,来架起应用程序到硬件之间的桥梁,并管理各种硬件资源,从而使应用程序得以专注自己的任务并忽略硬件的差别。Windows NT操作系统的基本结构如图1-1所示。
1-1.png
应用程序运行在用户层,在IA32架构下,用户层的程序只能受限地直接访问硬件(在Windows NT上此限制比较阉严格),因此,应用程序通过系统DLL提供的一组统一的规范的接口来执行与硬件相关的动作。这些DLL又通过调用Windows系统提供的服务与内核进行交互,从而将任务转交给内核。
调用系统服务并不一定需要通过系统DLL,应用程序完全可以自己实现。而且理论上,这种方法能使所有的用户层API HOOK失效,但是,微软并不保证系统服务调用接口是不变的,因此使用系统DLL提供的API可以更好地保障应用程序在不同系统版本间的兼容性。
有关系统服务的内容,请参考第五章:系统服务。
进入内核层,执行体为应用程序提供了系统服务的接口,而之下的内核则负责操作系统的基本功能,例如内存管理、进程和线程的管理与调度、中断管理等,并负责提供一些系统机制。在下方的硬件抽象层则将基本的硬件抽象为统一的接口,提供给内核中的各个模块。最后,具体的硬件管理工作则交给设备驱动程序。
在设备驱动程序和硬件抽象层之间,还有可能存在过滤驱动程序,用于过滤硬件抽象层和设备驱动程序直接的各种请求。

至于Windows子系统,则负责实现并管理图形设备接口和应用程序窗口(包含Windows消息机制)。而在Windows NT系统设计之初,还有可选的OS/2子系统和POSIX子系统,不过这已经成为历史,从Windows NT5.1开始随Windows发行的只有Windows子系统。
Windows子系统包含用户层部分(csrss.exe与一系列DLL)和内核层(XXXXXXXXXs)两部分,但相关话题并不在本文的讨论范围内。
+100  科创币    虎哥    2013/01/25 听课站位
+100  科创币    wesker    2013/01/25 -
来自:计算机科学 / 软件综合
9
已屏蔽 原因:{{ notice.reason }}已屏蔽
{{notice.noticeContent}}
~~空空如也
phpskycn 作者
12年0个月前 IP:未同步
491234
二、内存管理
操作系统的项基本功能就是管理物理内存,Windows NT系统通过IA32提供的虚拟内存机制为每一个进程提供了一个独立的、统一的虚拟内存空间。同时,系统负责对物理内存的管理和虚拟内存-物理内存之间映射关系的维护。
2.1物理内存管理
Windows NT系统对物理内存的管理并不是本文要介绍的内容,但由于和其它部分有所关联,因此在此之上简要得介绍一下相关的数据结构。
系统使用一个MMPFN结构的数组MmPfnDataBasee来描述每一物理内存页的情况。通过页帧号作为索引,可以很方便地使用MmPfnDataBasee数组查看物理页的情况,并找到相关的页表项以完成页交换。
大致的内存管理过程可以参考图2-0。
2-0.png
该结构的定义如下:

typedef struct _MMPFN {

    union {

        ULONG Flink;

        ULONG WsIndex;

        PKEVENT Event;

        NTSTATUS ReadStatus;

        struct _MMPFN *NextStackPfn;

        } u1;

    PMMPTE PteAddress;

    union {

        ULONG Blink;

        ULONG ShareCount;

        ULONG SecondaryColorFlink;

        } u2;

    union {

        MMPFNENTRY e1;

        struct {

            USHORT ShortFlags;

            USHORT ReferenceCount;

        } e2;

    } u3;

    MMPTE OriginalPte;

    ULONG PteFrame;

} MMPFN;

typedef MMPFN *PMMPFN;



什么是页帧号?这个结构在不同的情况下定义不同,可以理解为地址除去页内偏移后剩下的高位。地址转译的过程也和页帧号密切相关:通过虚拟地址中的各部分作为索引查表,得到最终的物理页帧号(这样就得到了物理地址中除了低12位页内偏移的其它部分),最终再以页内偏移为低位,就能得到物理地址)
2.2进程内存管理
现代操作系统通过“虚拟内存”机制为进程提供了独立的地址空间来防止相互干扰,并屏蔽了实际物理内存容量对应用程序的影响。应用程序面对的是统一的、完整的4GB地址空间,具体能使用的物理内存容量则由操作系统决定。
2.2.1平坦(FLAT)模式
运行在IA32架构下时,Windows NT系统打开了CPU的分页支持(并选择4KB小页面),但此时CPU的段机制仍然起作用。Windows NT通过特殊的机制,从而实现对段机制的屏蔽(平坦化)。
系统在启动后,将除FS外的所有的段描述符都设置为基地址为0,大小为0xffffffff,相当于每个段都指向了整个地址空间,所以无特殊情况下不用考虑纠结的段问题。但系统模式下和用户模式下段描述符依然有差异,主要是由于权限标志有所不同。至于FS段,指向了一个特殊的页面,主要用于异常处理,这里不作讨论。
通过这种“平坦”模式,段机制等于被屏蔽了,数据段和代码段以及栈都处在同一片地址区域中。应用程序的编写者无需考虑跨段访问等问题。
2.2.2进程地址空间
系统提供的进程地址空间为0x00000000-0x7fffffff,但这段空间中还有一些保留的区域,无法使用。
其中,0x00000000-0x0000FFFF为空指针保留区(为了使程序在使用空指针能产生异常以发现错误),0x7FFF0000-0x7FFFFFFF也被系统保留。其它部分可由用户程序使用,使用前需调用相关系统服务对对应的地址区域进行保留、提交操作。系统会根据参数修改对应的页表并分配物理页或者页文件。
在开启/3GB开关后,进程可访问的内存区域扩大到3GB,并且最后一块保留区域也相应地后移。
2.2.3用户层的虚拟内存管理
虽然页表在用户层无法访问的地址空间中,用户层无法操作,但NT系统提供了一系列API函数用于用户层的内存管理。
这些API通过调用系统服务切换到内核层后,以操作页表的方式来完成虚拟内存分配、权限设置等。应用程序虽然不能直接操作页表,但通过内存管理API依旧能完成大多数内存管理任务。
关于用户层的内存管理API不是本文的内容,可以参考《Windows核心编程》。
2.3 页表与地址转译
2.3.1页表与地址转译1:非PAE模式下
要完成虚拟内存到物理内存地址的翻译工作,就必须通过页表来实现映射。
如果直接使用单级的页表,一共需要4G/4K=1M=1048576个表项,在32位处理器上其占用内存空间为4MB(还算进了一些标志位占用的空间)。在考虑到每个进程都可能有一整份属于自己的页表,这样的内存开销即使对于现在的计算机仍然难以负担。所以Windows NT使用了多级页表机制。
对于32位Windows NT系统,使用2级页表,在打开了PAE(物理地址扩展,此功能在Pentium Pro处理器开始提供)后,则使用三级页表。
先来看不启用PAE的情况:
系统为每一个虚拟地址空间提供了一份PDE(页目录),其中包含1024个页目录项,每个页目录项指向一份页表,其包含的项数也是1024,每项内容为最终的物理地址的高20位。所以在转译地址时,CPU首先根据CR3寄存器的值获得页目录的基地址,然后由虚拟地址的高10(22-31位)为找到对应的页目录项,得到对应的页表的基地址在根据虚拟地址的中间10位(12-21位)在此页表中查找到最终的物理页基地址,最后,由此基地址加上虚拟地址中剩下的低12位(作为页偏移),得到最终的物理地址。
对于未启动PAE的IA32处理器,其PTE定义如下:

typedef struct _MMPTE_HARDWARE {
    ULONG Valid : 1;
#if defined(NT_UP)
    ULONG Write : 1;       // UP version
#else
    ULONG Writable : 1;    // changed for MP version
#endif
    ULONG Owner : 1;
    ULONG WriteThrough : 1;
    ULONG CacheDisable : 1;
    ULONG Accessed : 1;
    ULONG Dirty : 1;
    ULONG LargePage : 1;
    ULONG Global : 1;
    ULONG CopyOnWrite : 1; // software field
    ULONG Prototype : 1;   // software field
#if defined(NT_UP)
    ULONG reserved : 1;    // software field
#else
    ULONG Write : 1;       // software field - MP change
#endif
    ULONG PageFrameNumber : 20;
} MMPTE_HARDWARE, *PMMPTE_HARDWARE;

PDE与其定义相同。
但值得注意的是,LargePage位只有PDE启用,对于PTE无效。
PDE/PTE的结构中,最需要关注的就是其中的PageFrameNumber域,即页帧号。这里存储着转译过程中的下一级页表的虚拟地址的高位(低位用0填充)(对于PDE),或是物理页帧号的高位(对于PTE)。
具体关于PTE中各位的作用,请参阅《IA-32 架构软件开发人员手册》第三卷中的相关部分(XXXXXXXXXXXXXXXXXXXXXXXXX/products/processor/manual/325384.pdf)。
需要注意的是,只有当Valid位(有效位)被设置时(即PTE的第0位=1)时,该PTE对应的页在物理内存中,反之则需要进行页交换(需要从磁盘上的页面文件读取页内容并写入内存,同时在此之前可能需要将一个在内存中的页写入磁盘以腾出内存空间)。
对于PDE,上述法则依然适用。
非PAE模式下的地址转译过程可以参考图2-1:
2-1.png
2.3.2页面与地址转译:PAE模式下
由于现代计算机内存容量的迅猛增长,Intel在Pentium Pro处理器开始提供36根地址线(即提供36位物理寻址支持)并加入了PAE(物理地址扩展)的支持。开启PAE模式后(通过在控制寄存器CR4的第五位进行设置/检测),整个地址转译机制发生了一系列变化。
首先,Windows NT在PAE模式下采用三级页表,新增加了一个页目录指针索引项(高2位,即30-31位),PDE和PTE的索引均变为9位。
另外PDE和PTE的结构也发生了改变,具体如下:


typedef struct _X86PAE_HARDWARE_PDE {
    union {
        struct _X86PAE_HARDWARE_PTE Pte;

        struct {
            ULONGLONG Valid : 1;
            ULONGLONG Write : 1;
            ULONGLONG Owner : 1;
            ULONGLONG WriteThrough : 1;
            ULONGLONG CacheDisable : 1;
            ULONGLONG Accessed : 1;
            ULONGLONG Dirty : 1;
            ULONGLONG LargePage : 1;
            ULONGLONG Global : 1;
            ULONGLONG CopyOnWrite : 1;
            ULONGLONG Prototype : 1;
            ULONGLONG reserved0 : 1;
            ULONGLONG reserved2 : 9;
            ULONGLONG PageFrameNumber : 15;
            ULONGLONG reserved1 : 28;
        } Large;

        ULONGLONG QuadPart;
    };
} X86PAE_HARDWARE_PDE;

typedef struct _X86PAE_HARDWARE_PTE {
    union {
        struct {
            ULONGLONG Valid : 1;
            ULONGLONG Write : 1;
            ULONGLONG Owner : 1;
            ULONGLONG WriteThrough : 1;
            ULONGLONG CacheDisable : 1;
            ULONGLONG Accessed : 1;
            ULONGLONG Dirty : 1;
            ULONGLONG LargePage : 1;
            ULONGLONG Global : 1;
            ULONGLONG CopyOnWrite : 1; // software field
            ULONGLONG Prototype : 1;   // software field
            ULONGLONG reserved0 : 1;  // software field
            ULONGLONG PageFrameNumber : 24;
            ULONGLONG reserved1 : 28;  // software field
        };
        struct {
            ULONG LowPart;
            ULONG HighPart;
        };
    };
} X86PAE_HARDWARE_PTE, *PX86PAE_HARDWARE_PTE;

typedef X86PAE_HARDWARE_PTE X86PAE_HARDWARE_PDPTE;

处理器在进行地址转译时,首先由CR3寄存器得到页目录指针表基地址(CR3的高27位,注意开启PAE时CR3定义的变化),在由虚拟地址中的页目录指针表索引(高2位,30-31位)查表得到PDE的基地址,
然后以虚拟地址中的PDE索引(9位,21-29位)查得PTE基地址,再以虚拟地址中的PTE索引(9位,12-20位)查表得到对应的PTE项,以其中的页帧号(PageFrameNumber,24位)加上虚拟地址中的页偏移(0-11位)得到最终的物理地址(36位)。
关于页目录指针(PDPTE),未能找到其相关结构,倒是发现了其定义:

typedef X86PAE_HARDWARE_PTE X86PAE_HARDWARE_PDPTE;

由此可推断,其大小为64位,结构与PAE模式下的PTE相同。在调试中也发现,其高32位总是0。
PAE模式下的地址转译可以参考图2-2:
2-2.png
综上所述,在PAE模式下,地址转译发生了很大的变化,并且物理地址用64位量进行描述(虽然其为36位),且PDE和PTE的结构不再保持相同并各自有所变化。
2.3内核空间内存的一致性
Windows NT中虽然每个进程都有一份独立的页表(或者说是页目录/页目录指针)以为每个进程提供独立的地址空间(这样可以实现所谓的“进程隔离”:各个进程之间的数据相互独立),但对于内核空间,则保持地址的一致性(即各进程中属于内核的空间是共享的),操作系统通过在为新进程建立地址空间是拷贝同一份PDE来实现。
这样做的理由为了方便工作在内核层的代码直接的相互访问,或许,微软认为能在内核执行的代码一定是规范的、安全的和可信任的(实际往往不一定)。
2.4内存池,非换页内存
内存池不是本文要讨论的话题,但这里指出,一部分内存属于非换页内存池,即该部分的内存始终不会被交换到页文件中,这里往往存储这那些需要保证能被访问到的关键数据,比如页表,或者其它需要常驻内存的代码。
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
phpskycn作者
12年0个月前 IP:未同步
491429
三、进程与线程
3.1 NT系统中的进程和线程
前面已经介绍过,Windows NT系统下,每个进程都拥有属于自己的地址空间。不仅如此,在NT系统中,进程是程序运行的基本单位。一个应用程序被运行后,系统会为其创建一个进程。每个进程在运行时独享各种硬件资源(但并不意味着它一直占有这些资源,进程会被打断或者进入等待状态)。
至于线程,在NT系统中则必定属于某一个进程,属于同一进程的线程共享该进程的地址空间。在多线程(含多处理器)系统运行时,线程为每个逻辑核心所运行的基本单位,因此理论上每个线程都享有独立的全套寄存器资源(IA32架构下每个核心都拥有自己的全套寄存器,不过同步多线程技术模拟出的“逻辑核心”是否拥有全部的独立寄存器资源这里还不能肯定)。因此,一个进程必然包含一个线程(称为“主线程”)。
NT系统通过“时间片”来设置每个进程或是线程执行的时间,因此即使在仅拥有1个单核心单线程的处理器的系统上,仍然能使得用户感觉程序是“同步执行”的。这是因为每个线程运行的时间都非常短暂,用户感觉不到进程的切换。被切换出去的线程处于“等待”状态,系统会把与之相关的数据存储起来,在下次被切换回去的时候再次载入。有时候,这些相关的数据(主要是各寄存器的值)被称为“执行环境”。
还有一线程无法继续执行的情况就是引发了中断。Windows NT中,用户层线程的中断级别最低,任何中断都可以打断它的运行,直到中断处理结束(有可能中断处理会把线程杀死,这样这个线程就再也没有机会继续执行代码了)。关于中断的内容,请参考第四章。
需要明确的是,系统调度的对象是线程而不是进程。在一个多逻辑处理器的系统中,可能存在多个不同进程中的线程同时在执行的情况。
3.2NT系统的进程管理
系统用EPROCESS结构的对象描述描述一个进程,该结构的定义如下(这里给出了完整的定义,包含IA32E模式下的情况):

typedef struct _EPROCESS {
    KPROCESS Pcb;

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

    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.
    //

    LIST_ENTRY ActiveProcessLinks;

    //
    // Quota Fields.
    //

    SIZE_T QuotaUsage[PsQuotaTypes];
    SIZE_T QuotaPeak[PsQuotaTypes];
    SIZE_T CommitCharge;

    //
    // VmCounters.
    //

    SIZE_T PeakVirtualSize;
    SIZE_T VirtualSize;

    LIST_ENTRY SessionProcessLinks;

    PVOID DebugPort;
    PVOID ExceptionPort;
    PHANDLE_TABLE ObjectTable;

    //
    // Security.
    //

    EX_FAST_REF Token;

    PFN_NUMBER WorkingSetPage;
    KGUARDED_MUTEX AddressCreationLock;
    KSPIN_LOCK HyperSpaceLock;

    struct _ETHREAD *ForkInProgress;
    ULONG_PTR HardwareTrigger;

    PMM_AVL_TABLE PhysicalVadRoot;
    PVOID CloneRoot;
    PFN_NUMBER NumberOfPrivatePages;
    PFN_NUMBER NumberOfLockedPages;
    PVOID Win32Process;
    struct _EJOB *Job;
    PVOID SectionObject;

    PVOID SectionBaseAddress;

    PEPROCESS_QUOTA_BLOCK QuotaBlock;

    PPAGEFAULT_HISTORY WorkingSetWatch;
    HANDLE Win32WindowStation;
    HANDLE InheritedFromUniqueProcessId;

    PVOID LdtInformation;
    PVOID VadFreeHint;
    PVOID VdmObjects;
    PVOID DeviceMap;

    PVOID Spare0[3];
    union {
        HARDWARE_PTE PageDirectoryPte;
        ULONGLONG Filler;
    };
    PVOID Session;
    UCHAR ImageFileName[ 16 ];

    LIST_ENTRY JobLinks;
    PVOID LockedPagesList;

    LIST_ENTRY ThreadListHead;

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

    PVOID SecurityPort;

#ifdef _WIN64
    PWOW64_PROCESS Wow64Process;
#else
    PVOID PaeTop;
#endif

    ULONG ActiveThreads;

    ACCESS_MASK GrantedAccess;

    ULONG DefaultHardErrorProcessing;

    NTSTATUS LastThreadExitStatus;

    //
    // Peb
    //

    PPEB Peb;

    //
    // Pointer to the prefetches trace block.
    //
    EX_FAST_REF PrefetchTrace;

    LARGE_INTEGER ReadOperationCount;
    LARGE_INTEGER WriteOperationCount;
    LARGE_INTEGER OtherOperationCount;
    LARGE_INTEGER ReadTransferCount;
    LARGE_INTEGER WriteTransferCount;
    LARGE_INTEGER OtherTransferCount;

    SIZE_T CommitChargeLimit;
    SIZE_T CommitChargePeak;

    PVOID AweInfo;

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

    SE_AUDIT_PROCESS_CREATION_INFO SeAuditProcessCreationInfo;

    MMSUPPORT Vm;

#if !defined(_WIN64)
    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

    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 XXXXXXXm 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;
        };
    };

    NTSTATUS ExitStatus;

    USHORT NextPageColor;
    union {
        struct {
            UCHAR SubSystemMinorVersion;
            UCHAR SubSystemMajorVersion;
        };
        USHORT SubSystemVersion;
    };
    UCHAR PriorityClass;

    MM_AVL_TABLE VadRoot;

    ULONG Cookie;

} EPROCESS, *PEPROCESS;

这个结构比较复杂,这里只介绍其中的一部分。
首先看其中的pcb域和相关的KPROCESS结构:

typedef struct _KPROCESS {

    //
    // The dispatch header and profile listhead are fairly infrequently
    // referenced.
    //

    DISPATCHER_HEADER Header;
    LIST_ENTRY ProfileListHead;

    //
    // The following fields are referenced during context switches.
    //

    ULONG_PTR DirectoryTableBase[2];

#if defined(_X86_)

    KGDTENTRY LdtDescriptor;
    KIDTENTRY Int21Descriptor;
    USHORT IopmOffset;
    UCHAR Iopl;
    BOOLEAN Unused;

#endif

#if defined(_AMD64_)

    USHORT IopmOffset;

#endif

    volatile KAFFINITY ActiveProcessors;

    //
    // The following fields are referenced during clock interrupts.
    //

    ULONG KernelTime;
    ULONG UserTime;

    //
    // The following fields are referenced infrequently.
    //

    LIST_ENTRY ReadyListHead;
    SINGLE_LIST_ENTRY SwapListEntry;

#if defined(_X86_)

    PVOID VdmTrapcHandler;

#else

    PVOID Reserved1;

#endif

    LIST_ENTRY ThreadListHead;
    KSPIN_LOCK ProcessLock;
    KAFFINITY Affinity;

    //
    // N.B. The following bit number definitions must match the following
    //      bit field.
    //
    // N.B. These bits can only be written with interlocked operations.
    //

#define KPROCESS_AUTO_ALIGNMENT_BIT 0
#define KPROCESS_DISABLE_BOOST_BIT 1
#define KPROCESS_DISABLE_QUANTUM_BIT 2

    union {
        struct {
            LONG AutoAlignment : 1;
            LONG DisableBoost : 1;
            LONG DisableQuantum : 1;
            LONG ReservedFlags : 29;
        };
  
        LONG ProcessFlags;
    };

    SCHAR BasePriority;
    SCHAR QuantumReset;
    UCHAR State;
    UCHAR ThreadSeed;
    UCHAR PowerState;
    UCHAR IdealNode;
    BOOLEAN Visited;
    union {
        KEXECUTE_OPTIONS Flags;
        UCHAR ExecuteOptions;
    };

#if !defined(_X86_) && !defined(_AMD64_)

    PALIGNMENT_EXCEPTION_TABLE AlignmentExceptionTable;

#endif

    ULONG_PTR StackCount;
    LIST_ENTRY ProcessListEntry;
} KPROCESS, *PKPROCESS, *PRKPROCESS;


本文并不详细讲解NT系统的代码,所以不介绍整个结构,但下面会介绍其中一些重要的部分。
DirectoryTableBase[2]数组中的第一项记录着该进程页目录表的地址(PAE模式下为页目录指针表的地址),在进程切换时该地址中的一部分会被载入CR3控制寄存器(涉及地址转移,具体请参考第二张);第二项与该进程的超空间地址有关,关于超空间本文不介绍。
LdtDescriptor是该进程的局部描述符,Windows NT并不使用LDT。
IopmOffset指向IO权限表的位置,IO权限表可以用于控制进程的IO权限。
BasePriority为该进程的优先级,优先级的高低会影响分配到的时间片。
State则描述进程的状态(是否在内存中或者正在被交换)。
下面介绍EPROCESS结构中的其它部分:
DebugPort是该进程的调试端口句柄,某些反调试程序通过在此重复写入无效值来达到阻止单一进程被调试。
ExceptionPort则是异常端口句柄。
ObjectTable则是该进程的句柄表。句柄记录着一个进程已打开的对象,Windows经常通过句柄机制使用户层的应用程序可以访问一些内核对象。另外句柄表比较复杂,本文不作详细介绍。
Win32Process是指向Windows子系统管理的进程的指针。当此进程为控制台(CUI)进程时,此指针为NULL。通过这个指针可以判断一个进程是CUI进程还是GUI进程。
ImageFileName数组包含进程对应的映象文件的文件名中的前16个字符(不足16个字符时用0填充)。
ThreadListHead是该进程的线程链表的头节点,这个列表记录了该进程的所有线程,指向系统用于描述线程的ETHREAD中的ThreadListEntry域。
SeAuditProcessCreationInfo记录着进程被创建时完整的映象路径名。
3.3NT系统的线程管理
NT系统使用ETHREAD结构来描述线程,同样,该结构嵌套这KTHREAD结构

typedef struct _ETHREAD {
    KTHREAD Tcb;

    LARGE_INTEGER CreateTime;

    union {
        LARGE_INTEGER ExitTime;
        LIST_ENTRY LpcReplyChain;
        LIST_ENTRY KeyedWaitChain;
    };
    union {
        NTSTATUS ExitStatus;
        PVOID OfsChain;
    };

    //
    // Registry
    //

    LIST_ENTRY PostBlockList;

    //
    // Single linked list of termination blocks
    //

    union {
        //
        // List of termination ports
        //

        PTERMINATION_PORT TerminationPort;

        //
        // List of threads to be reaped. Only used at thread exit
        //

        struct _ETHREAD *ReaperLink;

        //
        // Keyvalue being waited for
        //
        PVOID KeyedWaitValue;

    };

    KSPIN_LOCK ActiveTimerListLock;
    LIST_ENTRY ActiveTimerListHead;

    CLIENT_ID Cid;

    //
    // Lpc
    //

    union {
        KSEMAPHORE LpcReplySemaphore;
        KSEMAPHORE KeyedWaitSemaphore;
    };

    union {
        PVOID LpcReplyMessage;          // -> Message that contains the reply
        PVOID LpcWaitingOnPort;
    };

    //
    // Security
    //
    //
    //    Client - If non null, indicates the thread is impersonating
    //        a client.
    //

    PPS_IMPERSONATION_INFORMATION ImpersonationInfo;

    //
    // Io
    //

    LIST_ENTRY IrpList;

    //
    //  File Systems
    //

    ULONG_PTR TopLevelIrp;  // either NULL, an Irp or a flag defined in FsRtl.h
    struct _DEVICE_OBJECT *DeviceToVerify;

    PEPROCESS ThreadsProcess;
    PVOID StartAddress;
    union {
        PVOID Win32StartAddress;
        ULONG LpcReceivedMessageId;
    };
    //
    // Ps
    //

    LIST_ENTRY ThreadListEntry;

    //
    // Rundown protection structure. Acquire this to do cross thread
    // TEB, TEB32 or stack references.
    //

    EX_RUNDOWN_REF RundownProtect;

    //
    // Lock to protect thread impersonation information
    //
    EX_PUSH_LOCK ThreadLock;

    ULONG LpcReplyMessageId;    // MessageId this thread is waiting for reply to

    ULONG ReadClusterSize;

    //
    // Client/server
    //

    ACCESS_MASK GrantedAccess;

    //
    // Flags for cross thread access. Use interlocked operations
    // via PS_SET_BITS etc.
    //

    //
    // Used to signify that the delete APC has been queued or the
    // thread has called PspExitThread itself.
    //

    #define PS_CROSS_THREAD_FLAGS_TERMINATED           0x00000001UL

    //
    // Thread create failed
    //

    #define PS_CROSS_THREAD_FLAGS_DEADTHREAD           0x00000002UL

    //
    // Debugger isn't shown this thread
    //

    #define PS_CROSS_THREAD_FLAGS_HIDEFROMDBG          0x00000004UL

    //
    // Thread is impersonating
    //

    #define PS_CROSS_THREAD_FLAGS_IMPERSONATING        0x00000008UL

    //
    // This is a system thread
    //

    #define PS_CROSS_THREAD_FLAGS_SYSTEM               0x00000010UL

    //
    // Hard errors are disabled for this thread
    //

    #define PS_CROSS_THREAD_FLAGS_HARD_ERRORS_DISABLED 0x00000020UL

    //
    // We should break in when this thread is terminated
    //

    #define PS_CROSS_THREAD_FLAGS_BREAK_ON_TERMINATION 0x00000040UL

    //
    // This thread should skip sending its create thread message
    //
    #define PS_CROSS_THREAD_FLAGS_SKIP_CREATION_MSG    0x00000080UL

    //
    // This thread should skip sending its final thread termination message
    //
    #define PS_CROSS_THREAD_FLAGS_SKIP_TERMINATION_MSG 0x00000100UL

    union {

        ULONG CrossThreadFlags;

        //
        // The following fields are for the debugger only. Do not use.
        // Use the bit definitions instead.
        //

        struct {
            ULONG Terminated              : 1;
            ULONG DeadThread              : 1;
            ULONG HideFromDebugger        : 1;
            ULONG ActiveImpersonationInfo : 1;
            ULONG SystemThread            : 1;
            ULONG HardErrorsAreDisabled   : 1;
            ULONG BreakOnTermination      : 1;
            ULONG SkipCreationMsg         : 1;
            ULONG SkipTerminationMsg      : 1;
        };
    };

    //
    // Flags to be accessed in this thread's context only at PASSIVE
    // level -- no need to use interlocked operations.
    //

    union {
        ULONG SameThreadPassiveFlags;

        struct {

            //
            // This thread is an active Ex worker thread; it should
            // not terminate.
            //

            ULONG ActiveExWorker : 1;
            ULONG ExWorkerCanWaitUser : 1;
            ULONG MemoryMaker : 1;

            //
            // Thread is active in the keyed event code. LPC should not run above this in an APC.
            //
            ULONG KeyedEventInUse : 1;
        };
    };

    //
    // Flags to be accessed in this thread's context only at APC_LEVEL.
    // No need to use interlocked operations.
    //

    union {
        ULONG SameThreadApcFlags;
        struct {

            //
            // The stored thread's MSGID is valid. This is only accessed
            // while the LPC mutex is held so it's an APC_LEVEL flag.
            //

            BOOLEAN LpcReceivedMsgIdValid : 1;
            BOOLEAN LpcExitThreadCalled   : 1;
            BOOLEAN AddressSpaceOwner     : 1;
            BOOLEAN OwnsProcessWorkingSetExclusive  : 1;
            BOOLEAN OwnsProcessWorkingSetShared     : 1;
            BOOLEAN OwnsSystemWorkingSetExclusive   : 1;
            BOOLEAN OwnsSystemWorkingSetShared      : 1;
            BOOLEAN OwnsSessionWorkingSetExclusive  : 1;
            BOOLEAN OwnsSessionWorkingSetShared     : 1;

            #define PS_SAME_THREAD_FLAGS_OWNS_A_WORKING_SET    0x000001F8UL

            BOOLEAN ApcNeeded                       : 1;
        };
    };

    BOOLEAN ForwardClusterOnly;
    BOOLEAN DisablePageFaultClustering;
    UCHAR ActiveFaultCount;

#if defined (PERF_DATA)
    ULONG PerformanceCountLow;
    LONG PerformanceCountHigh;
#endif

} ETHREAD, *PETHREAD;


typedef struct _KPROCESS {

    //
    // The dispatch header and profile listhead are fairly infrequently
    // referenced.
    //

    DISPATCHER_HEADER Header;
    LIST_ENTRY ProfileListHead;

    //
    // The following fields are referenced during context switches.
    //

    ULONG_PTR DirectoryTableBase[2];

#if defined(_X86_)

    KGDTENTRY LdtDescriptor;
    KIDTENTRY Int21Descriptor;
    USHORT IopmOffset;
    UCHAR Iopl;
    BOOLEAN Unused;

#endif

#if defined(_AMD64_)

    USHORT IopmOffset;

#endif

    volatile KAFFINITY ActiveProcessors;

    //
    // The following fields are referenced during clock interrupts.
    //

    ULONG KernelTime;
    ULONG UserTime;

    //
    // The following fields are referenced infrequently.
    //

    LIST_ENTRY ReadyListHead;
    SINGLE_LIST_ENTRY SwapListEntry;

#if defined(_X86_)

    PVOID VdmTrapcHandler;

#else

    PVOID Reserved1;

#endif

    LIST_ENTRY ThreadListHead;
    KSPIN_LOCK ProcessLock;
    KAFFINITY Affinity;

    //
    // N.B. The following bit number definitions must match the following
    //      bit field.
    //
    // N.B. These bits can only be written with interlocked operations.
    //

#define KPROCESS_AUTO_ALIGNMENT_BIT 0
#define KPROCESS_DISABLE_BOOST_BIT 1
#define KPROCESS_DISABLE_QUANTUM_BIT 2

    union {
        struct {
            LONG AutoAlignment : 1;
            LONG DisableBoost : 1;
            LONG DisableQuantum : 1;
            LONG ReservedFlags : 29;
        };
  
        LONG ProcessFlags;
    };

    SCHAR BasePriority;
    SCHAR QuantumReset;
    UCHAR State;
    UCHAR ThreadSeed;
    UCHAR PowerState;
    UCHAR IdealNode;
    BOOLEAN Visited;
    union {
        KEXECUTE_OPTIONS Flags;
        UCHAR ExecuteOptions;
    };

#if !defined(_X86_) && !defined(_AMD64_)

    PALIGNMENT_EXCEPTION_TABLE AlignmentExceptionTable;

#endif

    ULONG_PTR StackCount;
    LIST_ENTRY ProcessListEntry;
} KPROCESS, *PKPROCESS, *PRKPROCESS;

//
// Thread object
//

typedef enum _ADJUST_REASON {
    AdjustNone = 0,
    AdjustUnwait = 1,
    AdjustBoost = 2
} ADJUST_REASON;

#define ASSERT_THREAD(object) ASSERT((object)->Header.Type == ThreadObject)

//
// Define the number of times a user mode SLIST pop fault is permitted to be
// retried before raising an exception.
//

#define KI_SLIST_FAULT_COUNT_MAXIMUM 1024

typedef struct _KTHREAD {

    //
    // The dispatcher header and mutant listhead are fairly infrequently
    // referenced.
    //

    DISPATCHER_HEADER Header;
    LIST_ENTRY MutantListHead;

    //
    // The following fields are referenced during context switches and wait
    // operatings. They have been carefully laid out to get the best cache
    // hit ratios.
    //

    PVOID InitialStack;
    PVOID StackLimit;
    PVOID KernelStack;

    KSPIN_LOCK ThreadLock;
    union {
        KAPC_STATE ApcState;
        struct {
            UCHAR ApcStateFill[KAPC_STATE_ACTUAL_LENGTH];
            BOOLEAN ApcQueueable;
            volatile UCHAR NextProcessor;
            volatile UCHAR DeferredProcessor;
            UCHAR AdjustReason;
            SCHAR AdjustIncrement;
        };
    };

    KSPIN_LOCK ApcQueueLock;

#if !defined(_AMD64_)

    ULONG ContextSwitches;
    volatile UCHAR State;
    UCHAR NpxState;
    KIRQL WaitIrql;
    KPROCESSOR_MODE WaitMode;

#endif

    LONG_PTR WaitStatus;
    union {
        PKWAIT_BLOCK WaitBlockList;
        PKGATE GateObject;
    };

    BOOLEAN Alertable;
    BOOLEAN WaitNext;
    UCHAR WaitReason;
    SCHAR Priority;
    UCHAR EnableStackSwap;
    volatile UCHAR SwapBusy;
    BOOLEAN Alerted[MaximumMode];
    union {
        LIST_ENTRY WaitListEntry;
        SINGLE_LIST_ENTRY SwapListEntry;
    };

    PRKQUEUE Queue;

#if !defined(_AMD64_)

    ULONG WaitTime;
    union {
        struct {
            SHORT KernelApcDisable;
            SHORT SpecialApcDisable;
        };

        ULONG CombinedApcDisable;
    };

#endif

    PVOID Teb;
    union {
        KTIMER Timer;
        struct {
            UCHAR TimerFill[KTIMER_ACTUAL_LENGTH];

            //
            // N.B. The following bit number definitions must match the
            //      following bit field.
            //
            // N.B. These bits can only be written with interlocked
            //      operations.
            //
    
#define KTHREAD_AUTO_ALIGNMENT_BIT 0
#define KTHREAD_DISABLE_BOOST_BIT 1
    
            union {
                struct {
                    LONG AutoAlignment : 1;
                    LONG DisableBoost : 1;
                    LONG ReservedFlags : 30;
                };
        
                LONG ThreadFlags;
            };
        };
    };

    union {
        KWAIT_BLOCK WaitBlock[THREAD_WAIT_OBJECTS + 1];
        struct {
            UCHAR WaitBlockFill0[KWAIT_BLOCK_OFFSET_TO_BYTE0];
            BOOLEAN SystemAffinityActive;
        };

        struct {
            UCHAR WaitBlockFill1[KWAIT_BLOCK_OFFSET_TO_BYTE1];
            CCHAR PreviousMode;
        };

        struct {
            UCHAR WaitBlockFill2[KWAIT_BLOCK_OFFSET_TO_BYTE2];
            UCHAR ResourceIndex;
        };

        struct {
            UCHAR WaitBlockFill3[KWAIT_BLOCK_OFFSET_TO_BYTE3];
            UCHAR LargeStack;
        };

#if defined(_AMD64_)

        struct {
            UCHAR WaitBlockFill4[KWAIT_BLOCK_OFFSET_TO_LONG0];
            ULONG ContextSwitches;
        };

        struct {
            UCHAR WaitBlockFill5[KWAIT_BLOCK_OFFSET_TO_LONG1];
            volatile UCHAR State;
            UCHAR NpxState;
            KIRQL WaitIrql;
            KPROCESSOR_MODE WaitMode;
        };

        struct {
            UCHAR WaitBlockFill6[KWAIT_BLOCK_OFFSET_TO_LONG2];
            ULONG WaitTime;
        };

        struct {
            UCHAR WaitBlockFill7[KWAIT_BLOCK_OFFSET_TO_LONG3];
             union {
                 struct {
                     SHORT KernelApcDisable;
                     SHORT SpecialApcDisable;
                 };
        
                 ULONG CombinedApcDisable;
             };
        };

#endif

    };

    LIST_ENTRY QueueListEntry;

    //
    // The following fields are accessed during system service dispatch.
    //

    PKTRAP_FRAME TrapFrame;
    PVOID CallbackStack;
    PVOID ServiceTable;

#if defined(_AMD64_)

    ULONG KernelLimit;

#endif

    //
    // The following fields are referenced during ready thread and wait
    // completion.
    //

    UCHAR ApcStateIndex;
    UCHAR IdealProcessor;
    BOOLEAN Preempted;
    BOOLEAN ProcessReadyQueue;

#if defined(_AMD64_)

    PVOID Win32kTable;
    ULONG Win32kLimit;

#endif

    BOOLEAN KernelStackResident;
    SCHAR BasePriority;
    SCHAR PriorityDecrement;
    CHAR Saturation;
    KAFFINITY UserAffinity;
    PKPROCESS Process;
    KAFFINITY Affinity;

    //
    // The below fields are infrequently referenced.
    //

    PKAPC_STATE ApcStatePointer[2];
    union {
        KAPC_STATE SavedApcState;
        struct {
            UCHAR SavedApcStateFill[KAPC_STATE_ACTUAL_LENGTH];
            CCHAR FreezeCount;
            CCHAR SuspendCount;
            UCHAR UserIdealProcessor;
            UCHAR CalloutActive;

#if defined(_AMD64_)

            BOOLEAN CodePatchInProgress;

#elif defined(_X86_)

            UCHAR Iopl;

#else

            UCHAR OtherPlatformFill;

#endif

        };
    };

    PVOID Win32Thread;
    PVOID StackBase;
    union {
        KAPC SuspendApc;
        struct {
            UCHAR SuspendApcFill0[KAPC_OFFSET_TO_SPARE_BYTE0];
            SCHAR Quantum;
        };

        struct {
            UCHAR SuspendApcFill1[KAPC_OFFSET_TO_SPARE_BYTE1];
            UCHAR QuantumReset;
        };

        struct {
            UCHAR SuspendApcFill2[KAPC_OFFSET_TO_SPARE_LONG];
            ULONG KernelTime;
        };

        struct {
            UCHAR SuspendApcFill3[KAPC_OFFSET_TO_SYSTEMARGUMENT1];
            PVOID TlsArray;
        };

        struct {
            UCHAR SuspendApcFill4[KAPC_OFFSET_TO_SYSTEMARGUMENT2];
            PVOID BBTData;
        };

        struct {
            UCHAR SuspendApcFill5[KAPC_ACTUAL_LENGTH];
            UCHAR PowerState;
            ULONG UserTime;
        };
    };

    union {
        KSEMAPHORE SuspendSemaphore;
        struct {
            UCHAR SuspendSemaphorefill[KSEMAPHORE_ACTUAL_LENGTH];
            ULONG SListFaultCount;
        };
    };

    LIST_ENTRY ThreadListEntry;
    PVOID SListFaultAddress;

#if defined(_WIN64)

    LONG64 ReadOperationCount;
    LONG64 WriteOperationCount;
    LONG64 OtherOperationCount;
    LONG64 ReadTransferCount;
    LONG64 WriteTransferCount;
    LONG64 OtherTransferCount;

#endif

} KTHREAD, *PKTHREAD, *PRKTHREAD;


这个结构更加复杂。其中的各个域即使按重要性介绍,也可能需要介绍很多。请读者自学参考相关资料。

3.4线程的调度
为了保证资源不被某一线程独占,操作系统会为每个线程分配时间片。当某个线程的CPU时间消耗完时,系统会进行调度,让处于队列中等待的下一个线程得到执行。
事实上,系统将优先级不同的线程存储在不同的链表中,在调度时会优先选择优先级较高的线程。
线程的调度涉及大量操作系统代码和实现细节,本文不作介绍,图3-0A介绍了大致的情况。
3-0A.png
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
phpskycn作者
12年0个月前 IP:未同步
491430
四、Windows NT的中断处理
中断是硬件提供的体制,NT系统下大致的中断处理可以参考图4-0。
4-0.png
4.1 中断
正常情况下,处理器会按照指令流按顺序执行指令,但很可能有意外情况需要处理器暂时停止完成原先的任务,去处理各种紧急的情况。一个很简单的情况是:程序需要访问的数据不在物理内存中,就会产生“缺页中断”,处理器会将控制权先交给系统的内存管理器,待完成页交换后,再使原程序继续执行。
4.2 IA32架构的中断处理机制
这节简单地描述IA32架构下硬件的中断处理机制,如果希望能详细了解其中的每一个细节,请参考《IA-32 架构软件开发人员手册》。
当一个中断产生的时候,处理器会根据中断号去查找“中断描述符表”(IDT,有时称为中断向量表)。至于IDT的位置,CPU中有一个专门的寄存器IDTR用于保存IDT的指针。
IDT中每一个描述符为64位,内部记录了中断处理例程的地址和一些描述符。这些描述符中,DPL位用于记载中断的权限,以防止低权限代码访问敏感系统例程,另外I/T标志用来表述这个中断是中断还是陷阱。两者的区别是:中断会把EFLAGE寄存器中的IF位设置为0,从而暂时屏蔽中断(不可屏蔽中断不受影响),直到执行iret指令恢复该标志。同样,IA32处理器也通过中断的方式处理异常。
图4-1和图4-2是IA32手册中关于中断号(包含异常)的一些定义:
4-1.png
4-2.png   
图4-3是IA32手册中关于中断涉及到三种描述符的定义:
4-3.png
另外,当异常产生时(用int指令直接生成除外)CPU会把异常号入栈。
4.3 NT系统的中断和异常处理机制
Windows NT并不会完全控制中断的处理,只是在IDT表中填入了一些异常处理函数和一部分中断处理函数。以下是Windows NT下IDT的原型:

_IDT            label byte

IDTEntry        _KiTrap00, D_INT032             ; 0: Divide Error
IDTEntry        _KiTrap01, D_INT032             ; 1: DEBUG TRAP
IDTEntry        _KiTrap02, D_INT032             ; 2: NMI/NPX Error
IDTEntry        _KiTrap03, D_INT332             ; 3: Breakpoint
IDTEntry        _KiTrap04, D_INT332             ; 4: INTO
IDTEntry        _KiTrap05, D_INT032             ; 5: BOUND/Print Screen
IDTEntry        _KiTrap06, D_INT032             ; 6: Invalid Opcode
IDTEntry        _KiTrap07, D_INT032             ; 7: NPX Not Available
IDTEntry        _KiTrap08, D_INT032             ; 8: Double Exception
IDTEntry        _KiTrap09, D_INT032             ; 9: NPX Segment Overrun
IDTEntry        _KiTrap0A, D_INT032             ; A: Invalid TSS
IDTEntry        _KiTrap0B, D_INT032             ; B: Segment Not Present
IDTEntry        _KiTrap0C, D_INT032             ; C: Stack Fault
IDTEntry        _KiTrap0D, D_INT032             ; D: General Protection
IDTEntry        _KiTrap0E, D_INT032             ; E: Page Fault
IDTEntry        _KiTrap0F, D_INT032             ; F: Intel Reserved

IDTEntry        _KiTrap10, D_INT032             ;10: 486 coprocessor error
IDTEntry        _KiTrap11, D_INT032             ;11: 486 alignment
IDTEntry        _KiTrap0F, D_INT032             ;12: Intel Reserved
IDTEntry        _KiTrap0F, D_INT032             ;13: XMMI unmasked numeric exception
IDTEntry        _KiTrap0F, D_INT032             ;14: Intel Reserved
IDTEntry        _KiTrap0F, D_INT032             ;15: Intel Reserved
IDTEntry        _KiTrap0F, D_INT032             ;16: Intel Reserved
IDTEntry        _KiTrap0F, D_INT032             ;17: Intel Reserved

IDTEntry        _KiTrap0F, D_INT032             ;18: Intel Reserved
IDTEntry        _KiTrap0F, D_INT032             ;19: Intel Reserved
IDTEntry        _KiTrap0F, D_INT032             ;1A: Intel Reserved
IDTEntry        _KiTrap0F, D_INT032             ;1B: Intel Reserved
IDTEntry        _KiTrap0F, D_INT032             ;1C: Intel Reserved
IDTEntry        _KiTrap0F, D_INT032             ;1D: Intel Reserved
IDTEntry        _KiTrap0F, D_INT032             ;1E: Intel Reserved
IDTEntry        _KiTrap0F, D_INT032             ;1F: Reserved for APIC

;
; Note IDTEntry 0x21 is reserved for WOW apps.
;

        rept 2AH - (($ - _IDT)/8)
IDTEntry        0, 0                            invalid IDT entry
        endm
IDTEntry        _KiGetTickCount,  D_INT332          2A: KiGetTickCount service
IDTEntry        _KiCallbackReturn,  D_INT332        2B: KiCallbackReturn
IDTEntry        _KiRaiseAssertion,  D_INT332        2C: KiRaiseAssertion service
IDTEntry        _KiDebugService,  D_INT332          2D: debugger calls
IDTEntry        _KiSystemService, D_INT332          2E: system service calls
IDTEntry        _KiTrap0F, D_INT032                 ;2F: Reserved for APIC

以下是Windows NT5.1.2600(XP SP3)登录后通过调试得到的IDT信息。

00:    80543250 nt!KiTrap00
01:    805433cc nt!KiTrap01
02:    Task Selector = 0x0058
03:    805437e0 nt!KiTrap03
04:    80543960 nt!KiTrap04
05:    80543ac0 nt!KiTrap05
06:    80543c34 nt!KiTrap06
07:    805442ac nt!KiTrap07
08:    Task Selector = 0x0050
09:    805446b0 nt!KiTrap09
0a:    805447d0 nt!KiTrap0A
0b:    80544910 nt!KiTrap0B
0c:    80544b70 nt!KiTrap0C
0d:    80544e5c nt!KiTrap0D
0e:    80545570 nt!KiTrap0E
0f:    805458a8 nt!KiTrap0F
10:    805459c8 nt!KiTrap10
11:    80545b04 nt!KiTrap11
12:    Task Selector = 0x00A0
13:    80545c6c nt!KiTrap13
14:    805458a8 nt!KiTrap0F
15:    805458a8 nt!KiTrap0F
16:    805458a8 nt!KiTrap0F
17:    805458a8 nt!KiTrap0F
18:    805458a8 nt!KiTrap0F
19:    805458a8 nt!KiTrap0F
1a:    805458a8 nt!KiTrap0F
1b:    805458a8 nt!KiTrap0F
1c:    805458a8 nt!KiTrap0F
1d:    805458a8 nt!KiTrap0F
1e:    805458a8 nt!KiTrap0F
1f:    806e810c hal!HalpApicSpuriousService
20:    00000000
21:    00000000
22:    00000000
23:    00000000
24:    00000000
25:    00000000
26:    00000000
27:    00000000
28:    00000000
29:    00000000
2a:    80542a7e nt!KiGetTickCount
2b:    80542b80 nt!KiCallbackReturn
2c:    80542d30 nt!KiSetLowWaitHighThread
2d:    805436bc nt!KiDebugService
2e:    80542501 nt!KiSystemService
2f:    805458a8 nt!KiTrap0F
30:    80541bc0 nt!KiUnexpectedInterrupt0
31:    80541bca nt!KiUnexpectedInterrupt1
32:    80541bd4 nt!KiUnexpectedInterrupt2
33:    80541bde nt!KiUnexpectedInterrupt3
34:    80541be8 nt!KiUnexpectedInterrupt4
35:    80541bf2 nt!KiUnexpectedInterrupt5
36:    80541bfc nt!KiUnexpectedInterrupt6
37:    806e7864 hal!PicSpuriousService37
38:    80541c10 nt!KiUnexpectedInterrupt8
39:    80541c1a nt!KiUnexpectedInterrupt9
3a:    80541c24 nt!KiUnexpectedInterrupt10
3b:    80541c2e nt!KiUnexpectedInterrupt11
3c:    80541c38 nt!KiUnexpectedInterrupt12
3d:    806e8e2c hal!HalpApcInterrupt
3e:    80541c4c nt!KiUnexpectedInterrupt14
3f:    80541c56 nt!KiUnexpectedInterrupt15
40:    80541c60 nt!KiUnexpectedInterrupt16
41:    806e8c88 hal!HalpDispatchInterrupt
42:    80541c74 nt!KiUnexpectedInterrupt18
43:    80541c7e nt!KiUnexpectedInterrupt19
44:    80541c88 nt!KiUnexpectedInterrupt20
45:    80541c92 nt!KiUnexpectedInterrupt21
46:    80541c9c nt!KiUnexpectedInterrupt22
47:    80541ca6 nt!KiUnexpectedInterrupt23
48:    80541cb0 nt!KiUnexpectedInterrupt24
49:    80541cba nt!KiUnexpectedInterrupt25
4a:    80541cc4 nt!KiUnexpectedInterrupt26
4b:    80541cce nt!KiUnexpectedInterrupt27
4c:    80541cd8 nt!KiUnexpectedInterrupt28
4d:    80541ce2 nt!KiUnexpectedInterrupt29
4e:    80541cec nt!KiUnexpectedInterrupt30
4f:    80541cf6 nt!KiUnexpectedInterrupt31
50:    806e793c hal!HalpApicRebootService
51:    80541d0a nt!KiUnexpectedInterrupt33
52:    80541d14 nt!KiUnexpectedInterrupt34
53:    80541d1e nt!KiUnexpectedInterrupt35
54:    80541d28 nt!KiUnexpectedInterrupt36
55:    80541d32 nt!KiUnexpectedInterrupt37
56:    80541d3c nt!KiUnexpectedInterrupt38
57:    80541d46 nt!KiUnexpectedInterrupt39
58:    80541d50 nt!KiUnexpectedInterrupt40
59:    80541d5a nt!KiUnexpectedInterrupt41
5a:    80541d64 nt!KiUnexpectedInterrupt42
5b:    80541d6e nt!KiUnexpectedInterrupt43
5c:    80541d78 nt!KiUnexpectedInterrupt44
5d:    80541d82 nt!KiUnexpectedInterrupt45
5e:    80541d8c nt!KiUnexpectedInterrupt46
5f:    80541d96 nt!KiUnexpectedInterrupt47
60:    80541da0 nt!KiUnexpectedInterrupt48
61:    80541daa nt!KiUnexpectedInterrupt49
62:    89c93044 atapi!IdePortInterrupt (KINTERRUPT 89c93008)
63:    89a0d4f4 USBPORT!USBPORT_InterruptService (KINTERRUPT 89a0d4b8)
64:    80541dc8 nt!KiUnexpectedInterrupt52
65:    80541dd2 nt!KiUnexpectedInterrupt53
66:    80541ddc nt!KiUnexpectedInterrupt54
67:    80541de6 nt!KiUnexpectedInterrupt55
68:    80541df0 nt!KiUnexpectedInterrupt56
69:    80541dfa nt!KiUnexpectedInterrupt57
6a:    80541e04 nt!KiUnexpectedInterrupt58
6b:    80541e0e nt!KiUnexpectedInterrupt59
6c:    80541e18 nt!KiUnexpectedInterrupt60
6d:    80541e22 nt!KiUnexpectedInterrupt61
6e:    80541e2c nt!KiUnexpectedInterrupt62
6f:    80541e36 nt!KiUnexpectedInterrupt63
70:    80541e40 nt!KiUnexpectedInterrupt64
71:    80541e4a nt!KiUnexpectedInterrupt65
72:    80541e54 nt!KiUnexpectedInterrupt66
73:    89905044 SCSIPORT!ScsiPortInterrupt (KINTERRUPT 89905008)
             USBPORT!USBPORT_InterruptService (KINTERRUPT 89d02008)
74:    80541e68 nt!KiUnexpectedInterrupt68
75:    80541e72 nt!KiUnexpectedInterrupt69
76:    80541e7c nt!KiUnexpectedInterrupt70
77:    80541e86 nt!KiUnexpectedInterrupt71
78:    80541e90 nt!KiUnexpectedInterrupt72
79:    80541e9a nt!KiUnexpectedInterrupt73
7a:    80541ea4 nt!KiUnexpectedInterrupt74
7b:    80541eae nt!KiUnexpectedInterrupt75
7c:    80541eb8 nt!KiUnexpectedInterrupt76
7d:    80541ec2 nt!KiUnexpectedInterrupt77
7e:    80541ecc nt!KiUnexpectedInterrupt78
7f:    80541ed6 nt!KiUnexpectedInterrupt79
80:    80541ee0 nt!KiUnexpectedInterrupt80
81:    80541eea nt!KiUnexpectedInterrupt81
82:    89cfe044 atapi!IdePortInterrupt (KINTERRUPT 89cfe008)
83:    89d5a044 *** ERROR: Symbol file could not be found.  Defaulted to export symbols for XXXXXXXs -
vmci!DllUnload+0x7D6 (KINTERRUPT 89d5a008)
             VIDEOPRT!pVideoPortInterrupt (KINTERRUPT 89d01310)
             portcls!CKsShellRequestor::`scalar deleting destructor'+0x26 (KINTERRUPT 89d7c7e8)
84:    80541f08 nt!KiUnexpectedInterrupt84
85:    80541f12 nt!KiUnexpectedInterrupt85
86:    80541f1c nt!KiUnexpectedInterrupt86
87:    80541f26 nt!KiUnexpectedInterrupt87
88:    80541f30 nt!KiUnexpectedInterrupt88
89:    80541f3a nt!KiUnexpectedInterrupt89
8a:    80541f44 nt!KiUnexpectedInterrupt90
8b:    80541f4e nt!KiUnexpectedInterrupt91
8c:    80541f58 nt!KiUnexpectedInterrupt92
8d:    80541f62 nt!KiUnexpectedInterrupt93
8e:    80541f6c nt!KiUnexpectedInterrupt94
8f:    80541f76 nt!KiUnexpectedInterrupt95
90:    80541f80 nt!KiUnexpectedInterrupt96
91:    80541f8a nt!KiUnexpectedInterrupt97
92:    897c7824 serial!SerialCIsrSw (KINTERRUPT 897c77e8)
93:    89c96044 i8042prt!I8042KeyboardInterruptService (KINTERRUPT 89c96008)
94:    80541fa8 nt!KiUnexpectedInterrupt100
95:    80541fb2 nt!KiUnexpectedInterrupt101
96:    80541fbc nt!KiUnexpectedInterrupt102
97:    80541fc6 nt!KiUnexpectedInterrupt103
98:    80541fd0 nt!KiUnexpectedInterrupt104
99:    80541fda nt!KiUnexpectedInterrupt105
9a:    80541fe4 nt!KiUnexpectedInterrupt106
9b:    80541fee nt!KiUnexpectedInterrupt107
9c:    80541ff8 nt!KiUnexpectedInterrupt108
9d:    80542002 nt!KiUnexpectedInterrupt109
9e:    8054200c nt!KiUnexpectedInterrupt110
9f:    80542016 nt!KiUnexpectedInterrupt111
a0:    80542020 nt!KiUnexpectedInterrupt112
a1:    8054202a nt!KiUnexpectedInterrupt113
a2:    80542034 nt!KiUnexpectedInterrupt114
a3:    89c95044 i8042prt!I8042MouseInterruptService (KINTERRUPT 89c95008)
a4:    80542048 nt!KiUnexpectedInterrupt116
a5:    80542052 nt!KiUnexpectedInterrupt117
a6:    8054205c nt!KiUnexpectedInterrupt118
a7:    80542066 nt!KiUnexpectedInterrupt119
a8:    80542070 nt!KiUnexpectedInterrupt120
a9:    8054207a nt!KiUnexpectedInterrupt121
aa:    80542084 nt!KiUnexpectedInterrupt122
ab:    8054208e nt!KiUnexpectedInterrupt123
ac:    80542098 nt!KiUnexpectedInterrupt124
ad:    805420a2 nt!KiUnexpectedInterrupt125
ae:    805420ac nt!KiUnexpectedInterrupt126
af:    805420b6 nt!KiUnexpectedInterrupt127
b0:    805420c0 nt!KiUnexpectedInterrupt128
b1:    89dac044 ACPI!ACPIInterruptServiceRoutine (KINTERRUPT 89dac008)
b2:    89c4f824 serial!SerialCIsrSw (KINTERRUPT 89c4f7e8)
b3:    805420de nt!KiUnexpectedInterrupt131
b4:    898fd044 NDIS!ndisMIsr (KINTERRUPT 898fd008)
b5:    805420f2 nt!KiUnexpectedInterrupt133
b6:    805420fc nt!KiUnexpectedInterrupt134
b7:    80542106 nt!KiUnexpectedInterrupt135
b8:    80542110 nt!KiUnexpectedInterrupt136
b9:    8054211a nt!KiUnexpectedInterrupt137
ba:    80542124 nt!KiUnexpectedInterrupt138
bb:    8054212e nt!KiUnexpectedInterrupt139
bc:    80542138 nt!KiUnexpectedInterrupt140
bd:    80542142 nt!KiUnexpectedInterrupt141
be:    8054214c nt!KiUnexpectedInterrupt142
bf:    80542156 nt!KiUnexpectedInterrupt143
c0:    80542160 nt!KiUnexpectedInterrupt144
c1:    806e7ac0 hal!HalpBroadcastCallService
c2:    80542174 nt!KiUnexpectedInterrupt146
c3:    8054217e nt!KiUnexpectedInterrupt147
c4:    80542188 nt!KiUnexpectedInterrupt148
c5:    80542192 nt!KiUnexpectedInterrupt149
c6:    8054219c nt!KiUnexpectedInterrupt150
c7:    805421a6 nt!KiUnexpectedInterrupt151
c8:    805421b0 nt!KiUnexpectedInterrupt152
c9:    805421ba nt!KiUnexpectedInterrupt153
ca:    805421c4 nt!KiUnexpectedInterrupt154
cb:    805421ce nt!KiUnexpectedInterrupt155
cc:    805421d8 nt!KiUnexpectedInterrupt156
cd:    805421e2 nt!KiUnexpectedInterrupt157
ce:    805421ec nt!KiUnexpectedInterrupt158
cf:    805421f6 nt!KiUnexpectedInterrupt159
d0:    80542200 nt!KiUnexpectedInterrupt160
d1:    806e6e54 hal!HalpClockInterrupt
d2:    80542214 nt!KiUnexpectedInterrupt162
d3:    8054221e nt!KiUnexpectedInterrupt163
d4:    80542228 nt!KiUnexpectedInterrupt164
d5:    80542232 nt!KiUnexpectedInterrupt165
d6:    8054223c nt!KiUnexpectedInterrupt166
d7:    80542246 nt!KiUnexpectedInterrupt167
d8:    80542250 nt!KiUnexpectedInterrupt168
d9:    8054225a nt!KiUnexpectedInterrupt169
da:    80542264 nt!KiUnexpectedInterrupt170
db:    8054226e nt!KiUnexpectedInterrupt171
dc:    80542278 nt!KiUnexpectedInterrupt172
dd:    80542282 nt!KiUnexpectedInterrupt173
de:    8054228c nt!KiUnexpectedInterrupt174
df:    80542296 nt!KiUnexpectedInterrupt175
e0:    805422a0 nt!KiUnexpectedInterrupt176
e1:    806e8048 hal!HalpIpiHandler
e2:    805422b4 nt!KiUnexpectedInterrupt178
e3:    806e7dac hal!HalpLocalApicErrorService
e4:    805422c8 nt!KiUnexpectedInterrupt180
e5:    805422d2 nt!KiUnexpectedInterrupt181
e6:    805422dc nt!KiUnexpectedInterrupt182
e7:    805422e6 nt!KiUnexpectedInterrupt183
e8:    805422f0 nt!KiUnexpectedInterrupt184
e9:    805422fa nt!KiUnexpectedInterrupt185
ea:    80542304 nt!KiUnexpectedInterrupt186
eb:    8054230e nt!KiUnexpectedInterrupt187
ec:    80542318 nt!KiUnexpectedInterrupt188
ed:    80542322 nt!KiUnexpectedInterrupt189
ee:    80542329 nt!KiUnexpectedInterrupt190
ef:    80542330 nt!KiUnexpectedInterrupt191
f0:    80542337 nt!KiUnexpectedInterrupt192
f1:    8054233e nt!KiUnexpectedInterrupt193
f2:    80542345 nt!KiUnexpectedInterrupt194
f3:    8054234c nt!KiUnexpectedInterrupt195
f4:    80542353 nt!KiUnexpectedInterrupt196
f5:    8054235a nt!KiUnexpectedInterrupt197
f6:    80542361 nt!KiUnexpectedInterrupt198
f7:    80542368 nt!KiUnexpectedInterrupt199
f8:    8054236f nt!KiUnexpectedInterrupt200
f9:    80542376 nt!KiUnexpectedInterrupt201
fa:    8054237d nt!KiUnexpectedInterrupt202
fb:    80542384 nt!KiUnexpectedInterrupt203
fc:    8054238b nt!KiUnexpectedInterrupt204
fd:    806e85a8 hal!HalpProfileInterrupt
fe:    806e8748 hal!HalpPerfInterrupt
ff:    805423a0 nt!KiUnexpectedInterrupt207

可以看到,IDT中相当多的项目并未被使用(处理例程被指定为KiUnexpectedInterruptXX),内核程序可以自行操作IDT添加一个属于自己中断。
另外,NT系统还提供了中断对象机制来供内核程序使用,可以在不直接操作IDT的情况下添加自己的中断处理例程,这里不作介绍。
4.4Windows的中断优先级
IA32架构中的APIC(高级可编程中断控制器)提供了对中断优先级的支持,Windows NT在此基础上自定义了自己中断优先方案,称为中断请求级别(IRQL),优先级从0-31,数值越大优先级越高。

#define PASSIVE_LEVEL 0             // Passive release level
#define LOW_LEVEL 0                 // Lowest interrupt level
#define APC_LEVEL 1                 // APC interrupt level
#define DISPATCH_LEVEL 2            // Dispatcher level
#define PROFILE_LEVEL 27            // timer used for profiling.
#define CLOCK1_LEVEL 28             // Interval clock 1 level - Not used on x86
#define CLOCK2_LEVEL 28             // Interval clock 2 level
#define IPI_LEVEL 29                // Interprocessor interrupt level
#define POWER_LEVEL 30              // Power failure level
#define HIGH_LEVEL 31               // Highest interrupt level

PASSIVE_LEVEL 为最低的优先级别,用户进程的IRQL=PASSIVE_LEVEL ,所以可以被任何拥有更高级别的中断打断。
APC(异步过程调用)的优先级APC_LEVEL比PASSIVE_LEVEL 稍高,在此之上则是DISPATCH_LEVEL ,线程调度器和DPC(延时过程调用)的IRQL=DISPATCH_LEVEL 。
关于APC和DPC,本文不作介绍。
3-26的IRQL分配给硬件中断,在此之上则为关键的时钟中断和一些性能计数器设计的中断使用。硬件中断的优先问题还涉及到APIC本身,在这不作介绍。
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
phpskycn作者
12年0个月前 IP:未同步
491431
五、NT系统服务及其分发
5.1从应用程序的API调用到硬件
下面以一个很简单的例子,描述应用程序调用一个API到最终执行(完成和硬件相关动作)的过程,来介绍系统服务的作用:
BOOL WriteProcessMemory(
HANDLE hProcess,
LPVOID lpBaseAddress,
LPVOID lpBuffer,
DWORD nSize,
LPDWORD lpNumberOfBytesWritten
);
当将参数入栈的动作完成后,程序执行的是call WriteProcessMemory指令,但此时并不会直接跳转到该函数的地址,而是在PE结构中的IAT(输入表)中对应的桩代码,在桩代码中再通过JMP指令转移到对应的地址(在应用程序加载的Kernel32.dll中),。关于PE结构不是本文的内容。
Kernel32.dll中的 WriteProcessMemory()只是对参数作出了一些处理,就直接调用Ntdll.dll中的NtWriteVirtualMemory(),这个函数被称为存根函数(有时又称为Native API),它只是简单地填写了系统服务的调用号,随后将控制权转交给KiIntSystemCall()或者KiFastSystemCall()(具体选择哪个取决于CPU情况,Nt系统有巧妙的机制保证作出正确的选择,这里不作介绍),随后KiXXSystemCall()进入内核模式,内核模式中的KiSystemService()通过NtWriteVirtualMemory()填写的调用好查系统服务表(SSDT或者SSDT_Shadow,具体是哪张取决于调用者的线程类型,详细情况在下面几节介绍),查到内核中的NtWriteVirtualMemory()的地址,在NtWriteVirtualMemory()中,完成具体的操作(检查一下参数和执行环境,再向目标进程的指定位置写入指定内容……)。随后通过KiServiceExit()返回用户模式。
如果是一个需要使用其它硬件的API(比如需要写入硬盘),内核中又会将需要请求传给相关驱动程序。
Windows NT通过系统服务的机制,使得用户层的应用程序可以调用系统服务将对硬件的直接请求转交给系统。这样既不会限制应用程序的功能,又可以保障系统的安全(应用程序无法直接操作硬件)。
图5-1描述了调用过程
5-1.png
另外需要指出的是,在用户层中调用系统服务不一定要通过系统DLL,完全可以自行调用(参考后面几节内容)。但Windows提供的系统服务接口可能会发生变化,而系统DLL提供的API是统一的,所以通过系统DLL调用系统服务可以更好地保障版本兼容性。
5.2系统调用过程
5.2.1进入内核模式
要实现具体的和硬件相关的操作,必须进入具有执行相关指令权限的内核模式。IA32架构下可以通过门机制来完成用户模式(在Windows下是RING3)到内核模式(Windows下是RING0)的切换。Windows NT使用“中断门”来实现这一过程。
如果读者对第四章还有映象,应该会记得IDT中的0x2e项为system service calls,即系统服务调用。在调试中也可以发现Int 0x2e中断的处理例程为nt!KiSystemService,即系统服务分发函数。所以,Windows NT正是通过Int 0x2e中断来调用系统服务。
调用者除了需要执行指令调用系统服务外,还需要提供服务号(在Windows NT中,服务号存储在EAX寄存器中),另外还需要在栈中存入相关参数。随后,系统会在中断处理例程中完成寄存器的存储与切换,内核栈-用户栈的切换和相关参数的拷贝工作。
Intel从Pentium II处理器开始提供快速系统服务调用功能,可以使用sysenter指令替代int 0x2e,两者所作的事情相同,但sysenter速度更快。
5.2.2系统服务的分发
在通过中断进入内核模式后,需要进行系统服务分发,即将控制权转移到指定的系统服务处理函数。Windows NT使用了名为系统服务表(SSDT)的数据结构储存各个服务存储函数的地址,其为KSERVICE_TABLE_DESCRIPTOR 结构数组,该结构定义如下:

typedef struct _KSERVICE_TABLE_DESCRIPTOR {
    PULONG_PTR Base;
    PULONG Count;
    ULONG Limit;
    PUCHAR Number;
} KSERVICE_TABLE_DESCRIPTOR, *PKSERVICE_TABLE_DESCRIPTOR;

需要关心的成员如下:
Base域指向系统服务例程地址数组,Number指向记录参数长度的数组。
Windows NT对于CUI线程的调用请求,使用SSDT进行分发,对于GUI线程则使用SSDT_Shadow进行分发。
SSDT_Shadow中拷贝了基本的SSDT项,还额外增加了一些Windows子系统提供的服务(因为GUI由Windows子系统负责实现)。
Windows NT存在的SSDT数量和系统版本号相关,某些版本有空余的SSDT可供第三方使用,某些版本则没有。
服务分发函数根据EAX寄存器中的服务号,先由其中第12-13位得到表的索引,得到所使用的表的基地址,再由低12位(0-11位)得到系统服务索引,然后通过该索引由Base指向的地址数组得到具体例程地址,并通过Number指向的数组查得参数长度,在从用户栈拷贝指定长度的参数后,调用对应的服务例程。
5.2.4返回用户模式
服务例程在被调用时相关参数以及被拷贝到内核栈中,然后其会尝试完成请求。之间会调用一系列内核中的函数,也可能会向驱动程序传递请求。完成这些后,服务例程会保存好结果,再调用KiSystemExit()返回用户模式。
该函数会完成寄存器的恢复和内核栈-用户栈的切换,最后通过一些机制决定是使用sysexit指令或者是iret指令返回(这取决于进入内核的方式)。
5.3关于API HOOK
在了解了应用程序实现与硬件相关功能的系统服务调用过程后,我们可以参考图5-1来讨论一下API HOOK。
API HOOK是一种很常见的截取应用程序的系统调用的手段,具体请自行搜索。基本原理是在目标指令中插入自己的指令以获得控制权。
从调用顺序来看,常见的API HOOK手段如下:
用户层(RING3)
CALL Address HOOK:直接修改目标程序指令流中调用API的指令中的地址,这种实现方式不常见,因为搜索目标地址很可能要涉及硬编码,并不好用。
IAT HOOK:修改IAT中桩代码的跳转地址,这种方式层一度流行过,不过稍显麻烦,需要对PE结构有所了解。
RING3 Inline HOOK:将跳转代码(跳转到自己处理函数)注入系统DLL中,这种方式比较方便,曾经非常流行。
Native API HOOK:将跳转代码注入Native API 中,这种方式比较“底层”。
SystemCall HOOK:注入对象换成KiXXSystemCall函数。这种方式在Ring3看起来是最“底层”的,但效率很糟糕,因为所有SystemCall过程都要被检查。
绕过用户层API HOOK其实很简单:自己执行Int 0x2e或者sysenter指令调用系统服务就可以,用不着进行任何检测,就可以轻松绕过上述钩子。
内核层(Ring0)HOOK:
SSDT HOOK:
修改SSDT中相关系统服务处理例程的地址,换成自己的函数。这种HOOK方式在Ring0 HOOK刚出现时非常流行。因为SSDT的地址是一个导出变量,SSDT_Shadow的地址也可以在一些地方得到;这种HOOK能捕捉到几乎全部Ring3模式下的请求。
但这种HOOK很容易被检测:在指定版本系统下,这些服务例程地址通常是固定的。
RING 0 Iiline HOOK:在服务例程中注入跳转代码,隐蔽性稍强,但也比较容易检测。
RING 0 Deep Iiline HOOK:修改的位置换成服务例程中较深入的位置,比如某个要实现最终功能必被调用的函数的地址,隐蔽性较强。
另外还有一些涉及驱动的请求可以通过HOOK驱动程序中的各个部位,这不是本文的讨论范围。
六、相关学习资源
本文只是初略地介绍了Windows NT系统中的几个部分,如果想要详细了解Windows NT系统,可以参考下列学习资源:
代码类:
Windows Research Kernel V1.2:这是微软提供的"Windows NT研究内核”,基于Windows NT5.2(Windows Server 2003 SP1),内含大部分内核和执行体的部分的代码,包含32位/64位版本。还提供了一套编译工具,可以在许可协议下自行修改内核并编译、运行。
详细信息请参考:XXXXXXXXXXXXXXXXXXXXXXXX/education/facultyconnection/articles/XXXXXXXXXXXXXXXXXpx?cid=2416&c1=en-us&c2=0
ReactOS:React OS通过反汇编分析Windows运行原理并自行编写代码作为实现。其能提供的代码资源是最完整的。介绍:XXXXXXXXXXXXXXXXXXXXXXX/zh/ReactOS
泄漏版本的Windows NT代码
非法泄漏Windows NT代码并不是值得肯定的行为,但这些泄漏的代码包含着许多未曾公开的内容,作为学习资源,仍是一个不错的选择。
Windows NT 4.0和Windows NT5.0(Windows 2000 SP1)的代码曾经部分泄漏,包含了一部分组件的源码。
WDK,DDK:
微软提供的驱动开发包中包含不少例子,这些例子中的某些和Windows中的驱动程序息息相关,甚至一些头文件中包含着很多函数的声明和数据结构的定义。
书籍类:
《Windows内核原理与实现》,潘爱民著
其以WRK为主,详细地介绍了Windows内部的各种机制和实现过程。另外根据该书的前言,潘爱民博士在写著时得到了阅读Windows源代码的许可。
这本书对很多数据结构和系统中的关键过程作了深入的介绍,非常适合配合WRK使用。
《Windows内核情景分析》毛德操著
以ReactOS源码为参考,相对来讲,本书的内容比较丰富,并不乏深度。但ReactOS并不能完全替代Windows NT源码。
《深入解析Windows操作系统》:戴维.所罗门等著,此书第四版有中文版,最新的第六版介绍了Windows NT6发布以来的很多情况。作者同样得到了阅读Windows源代码的许可。
与《Windows内核原理与实现》相比,这本书介绍的范围更宽一些(涉及到了IA64架构下的情况,甚至有关于WOW64的部分),但不够深入且过于抽象。
个人认为这三本著作各有特点。《Windows内核原理与实现》侧重于深入地讲解Windows NT内核(特别是WRK涉及到部分),与内核中的代码、数据结构息息相关,《Windows内核情景分析》也侧重于代码,但ReactOS虽然没有WRK权威,但也不受WRK涉及到范围限制,不过这本书似乎更侧重从用户层的角度往内核看,偏重那些和用户层关系比较大的部分;个人感觉《Windows内核原理与实现》和,《Windows内核情景分析》可以很好地互补。
至于《深入解析Windows操作系统》,虽然没上述两本深入,但是可以很好的地补充他们没有涉及到的地方(虽然其中部分内容比较冷门,比如和IA64相关的内容。
另外《英特尔® 64 和 IA-32 架构软件开发人员手册》也是需要阅读的参考资料,很多硬件机制只有在这里才能找到详尽、权威的解释,不过很遗憾它没有官方的中文版本,也找不到完整的翻译版(如果您有,请联系我),而且其中含有大量晦涩的技术术语,阅读难度比较大。
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
phpskycn作者
12年0个月前 IP:未同步
491659
另外贴一份Windows 7(Windows 7 SP1 32位,即Windows NT 6.1.7601下的SSDT
首先:
dd KeServiceDescriptorTable
得到:

83d899c0  83c9dd9c 00000000 00000191 83c9e3e4
83d899d0  00000000 00000000 00000000 00000000
83d899e0  83cfc6af 00000000 0239dd4d 00000bb8
83d899f0  00000011 00000100 5385d2ba d717548f
83d89a00  83c9dd9c 00000000 00000191 83c9e3e4
83d89a10  94006000 00000000 00000339 9400702c
83d89a20  00000000 00000000 83d89a24 00000340
83d89a30  00000340 863f1a38 00000007 00000000

参考SSDT的结构:

typedef struct _KSERVICE_TABLE_DESCRIPTOR {
    PULONG_PTR Base;
    PULONG Count;
    ULONG Limit;
    PUCHAR Number;
} KSERVICE_TABLE_DESCRIPTOR, *PKSERVICE_TABLE_DESCRIPTOR;

可知
Base = 0x83c9dd9c
Limit = KSERVICE_TABLE_DESCRIPTOR + 8
即SSDT中有0x191个项,一共401项
然后
dds 83c9dd9c l 191

得到:

83c9dd9c  83e99c28 nt!NtAcceptConnectPort
83c9dda0  83ce040d nt!NtAccessCheck
83c9dda4  83e29b68 nt!NtAccessCheckAndAuditAlarm
83c9dda8  83c4488a nt!NtAccessCheckByType
83c9ddac  83e9b4ff nt!NtAccessCheckByTypeAndAuditAlarm
83c9ddb0  83d1d3fa nt!NtAccessCheckByTypeResultList
83c9ddb4  83f0bb05 nt!NtAccessCheckByTypeResultListAndAuditAlarm
83c9ddb8  83f0bb4e nt!NtAccessCheckByTypeResultListAndAuditAlarmByHandle
83c9ddbc  83e1e3bd nt!NtAddAtom
83c9ddc0  83f25368 nt!NtAddBootEntry
83c9ddc4  83f265c1 nt!NtAddDriverEntry
83c9ddc8  83e14b95 nt!NtAdjustGroupsToken
83c9ddcc  83ea5b35 nt!NtAdjustPrivilegesToken
83c9ddd0  83efe963 nt!NtAlertResumeThread
83c9ddd4  83e51a56 nt!NtAlertThread
83c9ddd8  83e216cc nt!NtAllocateLocallyUniqueId
83c9dddc  83db7928 nt!NtAllocateReserveObject
83c9dde0  83ef0898 nt!NtAllocateUserPhysicalPages
83c9dde4  83e0814e nt!NtAllocateUuids
83c9dde8  83e4aa62 nt!NtAllocateVirtualMemory
83c9ddec  83e96df1 nt!NtAlpcAcceptConnectPort
83c9ddf0  83df8238 nt!NtAlpcCancelMessage
83c9ddf4  83e961fe nt!NtAlpcConnectPort
83c9ddf8  83e15c0c nt!NtAlpcCreatePort
83c9ddfc  83ea75bc nt!NtAlpcCreatePortSection
83c9de00  83e1828f nt!NtAlpcCreateResourceReserve
83c9de04  83ea739c nt!NtAlpcCreateSectionView
83c9de08  83e9fafc nt!NtAlpcCreateSecurityContext
83c9de0c  83e2a0f0 nt!NtAlpcDeletePortSection
83c9de10  83eeb657 nt!NtAlpcDeleteResourceReserve
83c9de14  83e9cec9 nt!NtAlpcDeleteSectionView
83c9de18  83ea77ee nt!NtAlpcDeleteSecurityContext
83c9de1c  83e801fc nt!NtAlpcDisconnectPort
83c9de20  83e9af2e nt!NtAlpcImpersonateClientOfPort
83c9de24  83e2cd15 nt!NtAlpcOpenSenderProcess
83c9de28  83e20cf3 nt!NtAlpcOpenSenderThread
83c9de2c  83e12b70 nt!NtAlpcQueryInformation
83c9de30  83e80a83 nt!NtAlpcQueryInformationMessage
83c9de34  83eeb77f nt!NtAlpcRevokeSecurityContext
83c9de38  83e72f0a nt!NtAlpcSendWaitReceivePort
83c9de3c  83e20702 nt!NtAlpcSetInformation
83c9de40  83e3221b nt!NtApphelpCacheControl
83c9de44  83dee0e3 nt!NtAreMappedFilesTheSame
83c9de48  83e1fed1 nt!NtAssignProcessToJobObject
83c9de4c  83c9e8bc nt!NtCallbackReturn
83c9de50  83de95c3 nt!NtCancelIoFile
83c9de54  83e1dce7 nt!NtCancelIoFileEx
83c9de58  83ed7fb0 nt!NtCancelSynchronousIoFile
83c9de5c  83c4ad56 nt!NtCancelTimer
83c9de60  83e4cb5f nt!NtClearEvent
83c9de64  83e6537a nt!NtClose
83c9de68  83e9b42e nt!NtCloseObjectAuditAlarm
83c9de6c  83f13412 nt!NtCommitComplete
83c9de70  83f13132 nt!NtCommitEnlistment
83c9de74  83df49b9 nt!NtCommitTransaction
83c9de78  83ebd013 nt!NtCompactKeys
83c9de7c  83e1bc9d nt!NtCompareTokens
83c9de80  83e20ce9 nt!NtCompleteConnectPort
83c9de84  83ebd27f nt!NtCompressKey
83c9de88  83e98d09 nt!NtConnectPort
83c9de8c  83c60d0c nt!NtContinue
83c9de90  83ecdc79 nt!NtCreateDebugObject
83c9de94  83e23505 nt!NtCreateDirectoryObject
83c9de98  83dc5a55 nt!NtCreateEnlistment
83c9de9c  83e61671 nt!NtCreateEvent
83c9dea0  83f2b068 nt!NtCreateEventPair
83c9dea4  83e701e4 nt!NtCreateFile
83c9dea8  83e7b667 nt!NtCreateIoCompletion
83c9deac  83e12977 nt!NtCreateJobObject
83c9deb0  83f006de nt!NtCreateJobSet
83c9deb4  83e21e2a nt!NtCreateKey
83c9deb8  83e30d1e nt!NtCreateKeyedEvent
83c9debc  83df2a36 nt!NtCreateKeyTransacted
83c9dec0  83e2632f nt!NtCreateMailslotFile
83c9dec4  83e31196 nt!NtCreateMutant
83c9dec8  83ea14f9 nt!NtCreateNamedPipeFile
83c9decc  83dad406 nt!NtCreatePagingFile
83c9ded0  83e1275f nt!NtCreatePort
83c9ded4  83df457f nt!NtCreatePrivateNamespace
83c9ded8  83efcdf9 nt!NtCreateProcess
83c9dedc  83efce44 nt!NtCreateProcessEx
83c9dee0  83f2bafb nt!NtCreateProfile
83c9dee4  83f2bac1 nt!NtCreateProfileEx
83c9dee8  83dc835f nt!NtCreateResourceManager
83c9deec  83e43f2b nt!NtCreateSection
83c9def0  83e2698d nt!NtCreateSemaphore
83c9def4  83e227f5 nt!NtCreateSymbolicLinkObject
83c9def8  83efcc02 nt!NtCreateThread
83c9defc  83e91124 nt!NtCreateThreadEx
83c9df00  83e1f304 nt!NtCreateTimer
83c9df04  83e25ac8 nt!NtCreateToken
83c9df08  83df0e62 nt!NtCreateTransaction
83c9df0c  83dc816b nt!NtCreateTransactionManager
83c9df10  83e8f056 nt!NtCreateUserProcess
83c9df14  83dc5134 nt!NtCreateWaitablePort
83c9df18  83e30f39 nt!NtCreateWorkerFactory
83c9df1c  83eceb36 nt!NtDebugActiveProcess
83c9df20  83ecf1f3 nt!NtDebugContinue
83c9df24  83e4996f nt!NtDelayExecution
83c9df28  83e0d07b nt!NtDeleteAtom
83c9df2c  83f2539b nt!NtDeleteBootEntry
83c9df30  83f265f3 nt!NtDeleteDriverEntry
83c9df34  83db96ad nt!NtDeleteFile
83c9df38  83e0c911 nt!NtDeleteKey
83c9df3c  83eab9df nt!NtDeleteObjectAuditAlarm
83c9df40  83eb46f6 nt!NtDeletePrivateNamespace
83c9df44  83dfe328 nt!NtDeleteValueKey
83c9df48  83e943ca nt!NtDeviceIoControlFile
83c9df4c  83ee84da nt!NtDisableLastKnownGood
83c9df50  83f235ef nt!NtDisplayString
83c9df54  83d34259 nt!NtDrawText
83c9df58  83e524f0 nt!NtDuplicateObject
83c9df5c  83e8c974 nt!NtDuplicateToken
83c9df60  83ee85bb nt!NtEnableLastKnownGood
83c9df64  83f2559d nt!NtEnumerateBootEntries
83c9df68  83f267f3 nt!NtEnumerateDriverEntries
83c9df6c  83e87a59 nt!NtEnumerateKey
83c9df70  83f2517b nt!NtEnumerateSystemEnvironmentValuesEx
83c9df74  83f13f4c nt!NtEnumerateTransactionObject
83c9df78  83e89ebf nt!NtEnumerateValueKey
83c9df7c  83eeea0f nt!NtExtendSection
83c9df80  83e05d81 nt!NtFilterToken
83c9df84  83e118ff nt!NtFindAtom
83c9df88  83e29117 nt!NtFlushBuffersFile
83c9df8c  83db590f nt!NtFlushInstallUILanguage
83c9df90  83e204c2 nt!NtFlushInstructionCache
83c9df94  83dff9cd nt!NtFlushKey
83c9df98  83c451b1 nt!NtFlushProcessWriteBuffers
83c9df9c  83dfb130 nt!NtFlushVirtualMemory
83c9dfa0  83ef19b7 nt!NtFlushWriteBuffer
83c9dfa4  83ef1039 nt!NtFreeUserPhysicalPages
83c9dfa8  83cd94db nt!NtFreeVirtualMemory
83c9dfac  83cf36fc nt!NtFreezeRegistry
83c9dfb0  83f1439a nt!NtFreezeTransactions
83c9dfb4  83e766a2 nt!NtFsControlFile
83c9dfb8  83eb5dc1 nt!NtGetContextThread
83c9dfbc  83eb5d56 nt!NtGetCurrentProcessorNumber
83c9dfc0  83ef9e37 nt!NtGetDevicePowerState
83c9dfc4  83e31daf nt!NtGetMUIRegistryInfo
83c9dfc8  83efeb54 nt!NtGetNextProcess
83c9dfcc  83eadc0a nt!NtGetNextThread
83c9dfd0  83dfa5c6 nt!NtGetNlsSectionPtr
83c9dfd4  83f144f4 nt!NtGetNotificationResourceManager
83c9dfd8  83ddfe67 nt!NtGetPlugPlayEvent
83c9dfdc  83d0a5c7 nt!NtGetWriteWatch
83c9dfe0  83e167ca nt!NtImpersonateAnonymousToken
83c9dfe4  83eea7a1 nt!NtImpersonateClientOfPort
83c9dfe8  83e9a5fc nt!NtImpersonateThread
83c9dfec  83e7cf0d nt!NtInitializeNlsFiles
83c9dff0  83db91ca nt!NtInitializeRegistry
83c9dff4  83eb05c3 nt!NtInitiatePowerAction
83c9dff8  83eb1cdd nt!NtIsProcessInJob
83c9dffc  83ef9e1e nt!NtIsSystemResumeAutomatic
83c9e000  83db3de9 nt!NtIsUILanguageComitted
83c9e004  83db0c75 nt!NtListenPort
83c9e008  83de6b78 nt!NtLoadDriver
83c9e00c  83db2426 nt!NtLoadKey
83c9e010  83d9fa1c nt!NtLoadKey2
83c9e014  83dc2e72 nt!NtLoadKeyEx
83c9e018  83e2432b nt!NtLockFile
83c9e01c  83d99026 nt!NtLockProductActivationKeys
83c9e020  83d946d5 nt!NtLockRegistryKey
83c9e024  83c44191 nt!NtLockVirtualMemory
83c9e028  83de71b1 nt!NtMakePermanentObject
83c9e02c  83e2c851 nt!NtMakeTemporaryObject
83c9e030  83e3135b nt!NtMapCMFModule
83c9e034  83eefb57 nt!NtMapUserPhysicalPages
83c9e038  83ef012d nt!NtMapUserPhysicalPagesScatter
83c9e03c  83e67394 nt!NtMapViewOfSection
83c9e040  83f2556c nt!NtModifyBootEntry
83c9e044  83f267c4 nt!NtModifyDriverEntry
83c9e048  83e16db6 nt!NtNotifyChangeDirectoryFile
83c9e04c  83e1ae17 nt!NtNotifyChangeKey
83c9e050  83e19f39 nt!NtNotifyChangeMultipleKeys
83c9e054  83de0d6b nt!NtNotifyChangeSession
83c9e058  83e63584 nt!NtOpenDirectoryObject
83c9e05c  83f12995 nt!NtOpenEnlistment
83c9e060  83e30b92 nt!NtOpenEvent
83c9e064  83f2b169 nt!NtOpenEventPair
83c9e068  83e52b10 nt!NtOpenFile
83c9e06c  83ed7ca5 nt!NtOpenIoCompletion
83c9e070  83f00057 nt!NtOpenJobObject
83c9e074  83e6c642 nt!NtOpenKey
83c9e078  83e30add nt!NtOpenKeyEx
83c9e07c  83f2b49f nt!NtOpenKeyedEvent
83c9e080  83df0169 nt!NtOpenKeyTransacted
83c9e084  83df00f9 nt!NtOpenKeyTransactedEx
83c9e088  83e820e2 nt!NtOpenMutant
83c9e08c  83df94b2 nt!NtOpenObjectAuditAlarm
83c9e090  83dfaf07 nt!NtOpenPrivateNamespace
83c9e094  83e329dc nt!NtOpenProcess
83c9e098  83e84fff nt!NtOpenProcessToken
83c9e09c  83e72b37 nt!NtOpenProcessTokenEx
83c9e0a0  83d9e0c7 nt!NtOpenResourceManager
83c9e0a4  83e8a674 nt!NtOpenSection
83c9e0a8  83e060c6 nt!NtOpenSemaphore
83c9e0ac  83ea7977 nt!NtOpenSession
83c9e0b0  83e6eb6f nt!NtOpenSymbolicLinkObject
83c9e0b4  83e7ed87 nt!NtOpenThread
83c9e0b8  83e992e4 nt!NtOpenThreadToken
83c9e0bc  83e72c4e nt!NtOpenThreadTokenEx
83c9e0c0  83f2ae0f nt!NtOpenTimer
83c9e0c4  83f136f1 nt!NtOpenTransaction
83c9e0c8  83f14989 nt!NtOpenTransactionManager
83c9e0cc  83e04506 nt!NtPlugPlayControl
83c9e0d0  83e61970 nt!NtPowerInformation
83c9e0d4  83f132a2 nt!NtPrepareComplete
83c9e0d8  83f12fc2 nt!NtPrepareEnlistment
83c9e0dc  83f1335a nt!NtPrePrepareComplete
83c9e0e0  83f1307a nt!NtPrePrepareEnlistment
83c9e0e4  83e1793f nt!NtPrivilegeCheck
83c9e0e8  83de6f60 nt!NtPrivilegedServiceAuditAlarm
83c9e0ec  83e01a51 nt!NtPrivilegeObjectAuditAlarm
83c9e0f0  83f150e4 nt!NtPropagationComplete
83c9e0f4  83f151aa nt!NtPropagationFailed
83c9e0f8  83e63403 nt!NtProtectVirtualMemory
83c9e0fc  83eb45a7 nt!NtPulseEvent
83c9e100  83e789a1 nt!NtQueryAttributesFile
83c9e104  83f25a3e nt!NtQueryBootEntryOrder
83c9e108  83f25e83 nt!NtQueryBootOptions
83c9e10c  83ce3d34 nt!NtQueryDebugFilterState
83c9e110  83e97b8c nt!NtQueryDefaultLocale
83c9e114  83dc3f5c nt!NtQueryDefaultUILanguage
83c9e118  83e54d11 nt!NtQueryDirectoryFile
83c9e11c  83e799f0 nt!NtQueryDirectoryObject
83c9e120  83f26381 nt!NtQueryDriverEntryOrder
83c9e124  83db2b4a nt!NtQueryEaFile
83c9e128  83e1b81e nt!NtQueryEvent
83c9e12c  83ea15d5 nt!NtQueryFullAttributesFile
83c9e130  83e0d24c nt!NtQueryInformationAtom
83c9e134  83f12ba2 nt!NtQueryInformationEnlistment
83c9e138  83e766d5 nt!NtQueryInformationFile
83c9e13c  83ead0ff nt!NtQueryInformationJobObject
83c9e140  83eea7d4 nt!NtQueryInformationPort
83c9e144  83e57644 nt!NtQueryInformationProcess
83c9e148  83f145fe nt!NtQueryInformationResourceManager
83c9e14c  83e7dd6d nt!NtQueryInformationThread
83c9e150  83e7306e nt!NtQueryInformationToken
83c9e154  83f138e4 nt!NtQueryInformationTransaction
83c9e158  83d9dbcf nt!NtQueryInformationTransactionManager
83c9e15c  83d34e81 nt!NtQueryInformationWorkerFactory
83c9e160  83dffc3f nt!NtQueryInstallUILanguage
83c9e164  83f2be6b nt!NtQueryIntervalProfile
83c9e168  83ed7d68 nt!NtQueryIoCompletion
83c9e16c  83e6ccae nt!NtQueryKey
83c9e170  83e22e8d nt!NtQueryLicenseValue
83c9e174  83e01cc0 nt!NtQueryMultipleValueKey
83c9e178  83f2b57c nt!NtQueryMutant
83c9e17c  83e21ed6 nt!NtQueryObject
83c9e180  83ebcb05 nt!NtQueryOpenSubKeys
83c9e184  83eaadf8 nt!NtQueryOpenSubKeysEx
83c9e188  83e31277 nt!NtQueryPerformanceCounter
83c9e18c  83efd2c4 nt!NtQueryPortInformationProcess
83c9e190  83ed9349 nt!NtQueryQuotaInformationFile
83c9e194  83e979e6 nt!NtQuerySection
83c9e198  83e172d0 nt!NtQuerySecurityAttributesToken
83c9e19c  83e1ae4c nt!NtQuerySecurityObject
83c9e1a0  83f243fc nt!NtQuerySemaphore
83c9e1a4  83e6ec15 nt!NtQuerySymbolicLinkObject
83c9e1a8  83f245d3 nt!NtQuerySystemEnvironmentValue
83c9e1ac  83f24bc7 nt!NtQuerySystemEnvironmentValueEx
83c9e1b0  83e50cd4 nt!NtQuerySystemInformation
83c9e1b4  83e89ddd nt!NtQuerySystemInformationEx
83c9e1b8  83e97af7 nt!NtQuerySystemTime
83c9e1bc  83f2aece nt!NtQueryTimer
83c9e1c0  83e0d729 nt!NtQueryTimerResolution
83c9e1c4  83e6b405 nt!NtQueryValueKey
83c9e1c8  83e7c6a7 nt!NtQueryVirtualMemory
83c9e1cc  83e772c8 nt!NtQueryVolumeInformationFile
83c9e1d0  83e1ccaa nt!NtQueueApcThread
83c9e1d4  83e18e67 nt!NtQueueApcThreadEx
83c9e1d8  83c60d54 nt!NtRaiseException
83c9e1dc  83df80a3 nt!NtRaiseHardError
83c9e1e0  83e82c8c nt!NtReadFile
83c9e1e4  83db86a7 nt!NtReadFileScatter
83c9e1e8  83f13580 nt!NtReadOnlyEnlistment
83c9e1ec  83eea8b9 nt!NtReadRequestData
83c9e1f0  83e8082c nt!NtReadVirtualMemory
83c9e1f4  83f12b46 nt!NtRecoverEnlistment
83c9e1f8  83dc888c nt!NtRecoverResourceManager
83c9e1fc  83dca128 nt!NtRecoverTransactionManager
83c9e200  83f14f38 nt!NtRegisterProtocolAddressInformation
83c9e204  83efe09c nt!NtRegisterThreadTerminatePort
83c9e208  83e510ed nt!NtReleaseKeyedEvent
83c9e20c  83e49873 nt!NtReleaseMutant
83c9e210  83e33b6a nt!NtReleaseSemaphore
83c9e214  83ca3c28 nt!NtReleaseWorkerFactoryWorker
83c9e218  83e26a8e nt!NtRemoveIoCompletion
83c9e21c  83e21a8e nt!NtRemoveIoCompletionEx
83c9e220  83ecec81 nt!NtRemoveProcessDebug
83c9e224  83ebcd4b nt!NtRenameKey
83c9e228  83f14bd4 nt!NtRenameTransactionManager
83c9e22c  83ebc898 nt!NtReplaceKey
83c9e230  83cfc3d3 nt!NtReplacePartitionUnit
83c9e234  83e11a3d nt!NtReplyPort
83c9e238  83e595e2 nt!NtReplyWaitReceivePort
83c9e23c  83e59165 nt!NtReplyWaitReceivePortEx
83c9e240  83eeaa85 nt!NtReplyWaitReplyPort
83c9e244  83ea1435 nt!NtRequestPort
83c9e248  83e5e8d9 nt!NtRequestWaitReplyPort
83c9e24c  83dfcec3 nt!NtResetEvent
83c9e250  83d0ac18 nt!NtResetWriteWatch
83c9e254  83eb2904 nt!NtRestoreKey
83c9e258  83efe8fd nt!NtResumeProcess
83c9e25c  83e9134b nt!NtResumeThread
83c9e260  83f13636 nt!NtRollbackComplete
83c9e264  83f131ea nt!NtRollbackEnlistment
83c9e268  83dc6c7c nt!NtRollbackTransaction
83c9e26c  83f14d36 nt!NtRollforwardTransactionManager
83c9e270  83eb4176 nt!NtSaveKey
83c9e274  83eb391c nt!NtSaveKeyEx
83c9e278  83ebbbbb nt!NtSaveMergedKeys
83c9e27c  83e7edbc nt!NtSecureConnectPort
83c9e280  83dabf07 nt!NtSerializeBoot
83c9e284  83f25c7f nt!NtSetBootEntryOrder
83c9e288  83f2616b nt!NtSetBootOptions
83c9e28c  83efdcff nt!NtSetContextThread
83c9e290  83d919bd nt!NtSetDebugFilterState
83c9e294  83daf895 nt!NtSetDefaultHardErrorPort
83c9e298  83dc3ce1 nt!NtSetDefaultLocale
83c9e29c  83dc4250 nt!NtSetDefaultUILanguage
83c9e2a0  83f26bf5 nt!NtSetDriverEntryOrder
83c9e2a4  83ed8dda nt!NtSetEaFile
83c9e2a8  83e4a6de nt!NtSetEvent
83c9e2ac  83f240b7 nt!NtSetEventBoostPriority
83c9e2b0  83f2b435 nt!NtSetHighEventPair
83c9e2b4  83f2b367 nt!NtSetHighWaitLowEventPair
83c9e2b8  83ecf3b9 nt!NtSetInformationDebugObject
83c9e2bc  83f12dea nt!NtSetInformationEnlistment
83c9e2c0  83e7775c nt!NtSetInformationFile
83c9e2c4  83e1ccce nt!NtSetInformationJobObject
83c9e2c8  83ebc3ad nt!NtSetInformationKey
83c9e2cc  83e29314 nt!NtSetInformationObject
83c9e2d0  83e59603 nt!NtSetInformationProcess
83c9e2d4  83f1480c nt!NtSetInformationResourceManager
83c9e2d8  83e8aaaf nt!NtSetInformationThread
83c9e2dc  83e24780 nt!NtSetInformationToken
83c9e2e0  83f14146 nt!NtSetInformationTransaction
83c9e2e4  83f14dfb nt!NtSetInformationTransactionManager
83c9e2e8  83ccd362 nt!NtSetInformationWorkerFactory
83c9e2ec  83f2be48 nt!NtSetIntervalProfile
83c9e2f0  83e04b82 nt!NtSetIoCompletion
83c9e2f4  83ed7e8e nt!NtSetIoCompletionEx
83c9e2f8  83effd17 nt!NtSetLdtEntries
83c9e2fc  83f2b3d2 nt!NtSetLowEventPair
83c9e300  83f2b2fc nt!NtSetLowWaitHighEventPair
83c9e304  83ed995f nt!NtSetQuotaInformationFile
83c9e308  83e22626 nt!NtSetSecurityObject
83c9e30c  83f248cd nt!NtSetSystemEnvironmentValue
83c9e310  83f24edf nt!NtSetSystemEnvironmentValueEx
83c9e314  83e6f0ee nt!NtSetSystemInformation
83c9e318  83f41d7a nt!NtSetSystemPowerState
83c9e31c  83eb0e70 nt!NtSetSystemTime
83c9e320  83eb7b4d nt!NtSetThreadExecutionState
83c9e324  83ca3d52 nt!NtSetTimer
83c9e328  83cb64b9 nt!NtSetTimerEx
83c9e32c  83e11b3e nt!NtSetTimerResolution
83c9e330  83db32d7 nt!NtSetUuidSeed
83c9e334  83e2b427 nt!NtSetValueKey
83c9e338  83ed9979 nt!NtSetVolumeInformationFile
83c9e33c  83f235ad nt!NtShutdownSystem
83c9e340  83e339b7 nt!NtShutdownWorkerFactory
83c9e344  83ced701 nt!NtSignalAndWaitForSingleObject
83c9e348  83f134ca nt!NtSinglePhaseReject
83c9e34c  83f2bb84 nt!NtStartProfile
83c9e350  83f2bd7b nt!NtStopProfile
83c9e354  83efe89f nt!NtSuspendProcess
83c9e358  83eb5e2d nt!NtSuspendThread
83c9e35c  83ea6464 nt!NtSystemDebugControl
83c9e360  83e1336f nt!NtTerminateJobObject
83c9e364  83e7b9bf nt!NtTerminateProcess
83c9e368  83e99334 nt!NtTerminateThread
83c9e36c  83e90afa nt!NtTestAlert
83c9e370  83cf375f nt!NtThawRegistry
83c9e374  83f14478 nt!NtThawTransactions
83c9e378  83e709bb nt!NtTraceControl
83c9e37c  83ce66a0 nt!NtTraceEvent
83c9e380  83f26df9 nt!NtTranslateFilePath
83c9e384  83eea74b nt!NtUmsThreadYield
83c9e388  83eda1cf nt!NtUnloadDriver
83c9e38c  83ea9503 nt!NtUnloadKey
83c9e390  83ea951d nt!NtUnloadKey2
83c9e394  83ebbd53 nt!NtUnloadKeyEx
83c9e398  83e26eaf nt!NtUnlockFile
83c9e39c  83c3cb17 nt!NtUnlockVirtualMemory
83c9e3a0  83e8563a nt!NtUnmapViewOfSection
83c9e3a4  83f18769 nt!NtVdmControl
83c9e3a8  83eceed7 nt!NtWaitForDebugEvent
83c9e3ac  83e50e16 nt!NtWaitForKeyedEvent
83c9e3b0  83e49435 nt!NtWaitForMultipleObjects
83c9e3b4  83ef4904 nt!NtWaitForMultipleObjects32
83c9e3b8  83e48ae7 nt!NtWaitForSingleObject
83c9e3bc  83ca37b1 nt!NtWaitForWorkViaWorkerFactory
83c9e3c0  83f2b293 nt!NtWaitHighEventPair
83c9e3c4  83f2b22a nt!NtWaitLowEventPair
83c9e3c8  83cdc4b4 nt!NtWorkerFactoryWorkerReady
83c9e3cc  83e8ff2b nt!NtWriteFile
83c9e3d0  83dc02f7 nt!NtWriteFileGather
83c9e3d4  83eea926 nt!NtWriteRequestData
83c9e3d8  83e8071c nt!NtWriteVirtualMemory
83c9e3dc  83c4b5c5 nt!NtYieldExecution

其它几个域就用不着给出了吧。。。
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
phpskycn作者
11年11个月前 IP:未同步
491871
修订版1增加了一些内容和配图。(2013-01-26)
修订版2修正了第三章中存在的错误。(2013-02-06)
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论

想参与大家的讨论?现在就 登录 或者 注册

所属专业
所属分类
上级专业
同级专业
phpskycn
专家 老干部 学者 机友 笔友
文章
402
回复
4591
学术分
8
2009/03/15注册,2个月5天前活动

CV

主体类型:个人
所属领域:无
认证方式:手机号
IP归属地:未同步
文件下载
加载中...
{{errorInfo}}
{{downloadWarning}}
你在 {{downloadTime}} 下载过当前文件。
文件名称:{{resource.defaultFile.name}}
下载次数:{{resource.hits}}
上传用户:{{uploader.username}}
所需积分:{{costScores}},{{holdScores}}下载当前附件免费{{description}}
积分不足,去充值
文件已丢失

当前账号的附件下载数量限制如下:
时段 个数
{{f.startingTime}}点 - {{f.endTime}}点 {{f.fileCount}}
视频暂不能访问,请登录试试
仅供内部学术交流或培训使用,请先保存到本地。本内容不代表科创观点,未经原作者同意,请勿转载。
音频暂不能访问,请登录试试
支持的图片格式:jpg, jpeg, png
插入公式
评论控制
加载中...
文号:{{pid}}
投诉或举报
加载中...
{{tip}}
请选择违规类型:
{{reason.type}}

空空如也

加载中...
详情
详情
推送到专栏从专栏移除
设为匿名取消匿名
查看作者
回复
只看作者
加入收藏取消收藏
收藏
取消收藏
折叠回复
置顶取消置顶
评学术分
鼓励
设为精选取消精选
管理提醒
编辑
通过审核
评论控制
退修或删除
历史版本
违规记录
投诉或举报
加入黑名单移除黑名单
查看IP
{{format('YYYY/MM/DD HH:mm:ss', toc)}}