中国IT动力,最新最全的IT技术教程
最新100篇 | 推荐100篇 | 专题100篇 | 排行榜 | 搜索 | 在线API文档
首 页 | 程序开发 | 操作系统 | 软件应用 | 图形图象 | 网络应用 | 精文荟萃 | 教育认证 | 硬件维护 | 未整理篇 | 站长教程
ASP JS PHP工程 ASP.NET 网站建设 UML J2EESUN .NET VC VB VFP 网络维护 数据库 DB2 SQL2000 Oracle Mysql
服务器 Win2000 Office C DreamWeaver FireWorks Flash PhotoShop 上网宝典 CorelDraw 协议大全 网络安全 微软认证
硬件维护  CPU  主板  硬盘  内存  显卡  显示器  键盘鼠标  声卡音箱  打印机  机箱电源  BIOS  网卡  C#  Java  Delphi  vs.net2005
  当前位置:> 程序开发 > 编程语言 > 综合其它
《Undocumented Windows 2000 Secrets》翻译 --- 第七章(4)
作者:未知 时间:2005-07-27 23:26 出处:CSDN 责编:chinaitpower
              摘要:《Undocumented Windows 2000 Secrets》翻译 --- 第七章(4)

第七章  Windows 2000的对象管理

翻译:Kendiv( fcczj@263.net )

更新:Sunday, May 22, 2005

 

声明:转载请注明出处,并保证文章的完整性,本人保留译文的所有权利。

 

线程和进程环境块

你可能会很困惑:KTHREADEPROCESS结构中的TebPeb成员有什么实际价值?Teb,指向一个线程环境块(TEB),见列表7-18TEB的第一部分是线程信息块(Thread Information BlockNT_TIB),该结构在DDKntddk.hSDKwinnt.h中均有定义,其他部分则没有相应的文档记载。Windows 2000为系统中的每个线程维护一个TEB结构。在当前进程的地址空间中,其下属线程的TEB被映射到线性地址0x7FFDE0000x7FFDD0000x7FFDC000以此类推,每个线程均占用一个完整的4KB页。就像在第四章提到的那样,在用户模式下仍可通过FS:0x18来访问当前线程的TEBFS:0x18处存放的是内嵌的NT_TIBSelf成员。该成员总是指向其所在TEB的线性地址(该线性地址位于当前线程的4GB地址空间中)。

 

// typedef struct _NT_TIB // see winnt.h / ntddk.h

//         {

// /*000*/ struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList;

// /*004*/ PVOID                                  StackBase;

// /*008*/ PVOID                                  StackLimit;

// /*00C*/ PVOID                                  SubSystemTib;

// /*010*/ union

//             {

// /*010*/     PVOID FiberData;

// /*010*/     ULONG Version;

//             };

// /*014*/ PVOID           ArbitraryUserPointer;

// /*018*/ struct _NT_TIB *Self;

// /*01C*/ }

//         NT_TIB,

//      * PNT_TIB,

//     **PPNT_TIB;

 

// -----------------------------------------------------------------

// located at 0x7FFDE000, 0x7FFDD000, ...

 

typedef struct _TEB

        {

/*000*/ NT_TIB    Tib;

/*01C*/ PVOID     EnvironmentPointer;

/*020*/ CLIENT_ID Cid;

/*028*/ HANDLE    RpcHandle;

/*02C*/ PPVOID    ThreadLocalStorage;

/*030*/ PPEB      Peb;

/*034*/ DWORD     LastErrorValue;

/*038*/ }

        TEB,

     * PTEB,

    **PPTEB;

 

#define TEB_ \

        sizeof (TEB)

列表7-18.   线程环境块(TEB

 

就像每个线程都用于各自的TEB一样,每个进程也有与之相关的PEB(进程环境块)。PEB结构要比TEB复杂得多,如列表7-19所示。PEB结构包含多个指向各种子结构的指针,这些子结构又引用了更多的子结构,而且这些子结构大多都没有相应的文档。列表7-19中包含其中一些子结构的原始草图,很多成员的名字都是假设的。PEB位于线性地址:0x7FFDF000处,这意味着,TEB堆栈之后的第一个4KB页存放的就是PEB。这样系统通过当前线程的TEB结构中的Peb成员就可很容易的访问PEB结构。

 

typedef struct _MODULE_HEADER

        {

/*000*/ DWORD      d000;

/*004*/ DWORD      d004;

/*008*/ LIST_ENTRY List1;

/*010*/ LIST_ENTRY List2;

/*018*/ LIST_ENTRY List3;

/*020*/ }

        MODULE_HEADER,

     * PMODULE_HEADER,

    **PPMODULE_HEADER;

 

#define MODULE_HEADER_ \

        sizeof (MODULE_HEADER)

 

// -----------------------------------------------------------------

 

typedef struct _PROCESS_MODULE_INFO

        {

/*000*/ DWORD         Size; // 0x24

/*004*/ MODULE_HEADER ModuleHeader;

/*024*/ }

        PROCESS_MODULE_INFO,

     * PPROCESS_MODULE_INFO,

    **PPPROCESS_MODULE_INFO;

 

#define PROCESS_MODULE_INFO_ \

        sizeof (PROCESS_MODULE_INFO)

 

// -----------------------------------------------------------------

// see RtlCreateProcessParameters()

 

typedef struct _PROCESS_PARAMETERS

        {

/*000*/ DWORD          Allocated;

/*004*/ DWORD          Size;

/*008*/ DWORD          Flags; // bit 0: all pointers normalized

/*00C*/ DWORD          Reserved1;

/*010*/ LONG           Console;

/*014*/ DWORD          ProcessGroup;

/*018*/ HANDLE         StdInput;

/*01C*/ HANDLE         StdOutput;

/*020*/ HANDLE         StdError;

/*024*/ UNICODE_STRING WorkingDirectoryName;

/*02C*/ HANDLE         WorkingDirectoryHandle;

/*030*/ UNICODE_STRING SearchPath;

/*038*/ UNICODE_STRING ImagePath;

/*040*/ UNICODE_STRING CommandLine;

/*048*/ PWORD          Environment;

/*04C*/ DWORD          X;

/*050*/ DWORD          Y;

/*054*/ DWORD          XSize;

/*058*/ DWORD          YSize;

/*05C*/ DWORD          XCountChars;

/*060*/ DWORD          YCountChars;

/*064*/ DWORD          FillAttribute;

/*068*/ DWORD          Flags2;

/*06C*/ WORD           ShowWindow;

/*06E*/ WORD           Reserved2;

/*070*/ UNICODE_STRING Title;

/*078*/ UNICODE_STRING Desktop;

/*080*/ UNICODE_STRING Reserved3;

/*088*/ UNICODE_STRING Reserved4;

/*090*/ }

        PROCESS_PARAMETERS,

     * PPROCESS_PARAMETERS,

    **PPPROCESS_PARAMETERS;

 

#define PROCESS_PARAMETERS_ \

        sizeof (PROCESS_PARAMETERS)

 

// -----------------------------------------------------------------

 

typedef struct _SYSTEM_STRINGS

        {

/*000*/ UNICODE_STRING SystemRoot;       // d:\WINNT

/*008*/ UNICODE_STRING System32Root;     // d:\WINNT\System32

/*010*/ UNICODE_STRING BaseNamedObjects; // \BaseNamedObjects

/*018*/ }

        SYSTEM_STRINGS,

     * PSYSTEM_STRINGS,

    **PPSYSTEM_STRINGS;

 

#define SYSTEM_STRINGS_ \

        sizeof (SYSTEM_STRINGS)

 

// -----------------------------------------------------------------

 

typedef struct _TEXT_INFO

        {

/*000*/ PVOID           Reserved;

/*004*/ PSYSTEM_STRINGS SystemStrings;

/*008*/ }

        TEXT_INFO,

     * PTEXT_INFO,

    **PPTEXT_INFO;

 

#define TEXT_INFO_ \

        sizeof (TEXT_INFO)

 

// -----------------------------------------------------------------

// located at 0x7FFDF000

 

typedef struct _PEB

        {

/*000*/ BOOLEAN              InheritedAddressSpace;

/*001*/ BOOLEAN              ReadImageFileExecOptions;

/*002*/ BOOLEAN              BeingDebugged;

/*003*/ BYTE                 b003;

/*004*/ DWORD                d004;

/*008*/ PVOID                SectionBaseAddress;

/*00C*/ PPROCESS_MODULE_INFO ProcessModuleInfo;

/*010*/ PPROCESS_PARAMETERS  ProcessParameters;

/*014*/ DWORD                SubSystemData;

/*018*/ HANDLE               ProcessHeap;

/*01C*/ PCRITICAL_SECTION    FastPebLock;

/*020*/ PVOID                AcquireFastPebLock; // function

/*024*/ PVOID                ReleaseFastPebLock; // function

/*028*/ DWORD                d028;

/*02C*/ PPVOID               User32Dispatch;     // function

/*030*/ DWORD                d030;

/*034*/ DWORD                d034;

/*038*/ DWORD                d038;

/*03C*/ DWORD                TlsBitMapSize;      // number of bits

/*040*/ PRTL_BITMAP          TlsBitMap;          // ntdll!TlsBitMap

/*044*/ DWORD                TlsBitMapData [2];  // 64 bits

/*04C*/ PVOID                p04C;

/*050*/ PVOID                p050;

/*054*/ PTEXT_INFO           TextInfo;

/*058*/ PVOID                InitAnsiCodePageData;

/*05C*/ PVOID                InitOemCodePageData;

/*060*/ PVOID                InitUnicodeCaseTableData;

/*064*/ DWORD                KeNumberProcessors;

/*068*/ DWORD                NtGlobalFlag;

/*06C*/ DWORD                d6C;

/*070*/ LARGE_INTEGER        MmCriticalSectionTimeout;

/*078*/ DWORD                MmHeapSegmentReserve;

/*07C*/ DWORD                MmHeapSegmentCommit;

/*080*/ DWORD                MmHeapDeCommitTotalFreeThreshold;

/*084*/ DWORD                MmHeapDeCommitFreeBlockThreshold;

/*088*/ DWORD                NumberOfHeaps;

/*08C*/ DWORD                AvailableHeaps; // 16, *2 if exhausted

/*090*/ PHANDLE              ProcessHeapsListBuffer;

/*094*/ DWORD                d094;

/*098*/ DWORD                d098;

/*09C*/ DWORD                d09C;

/*0A0*/ PCRITICAL_SECTION    LoaderLock;

/*0A4*/ DWORD                NtMajorVersion;

/*0A8*/ DWORD                NtMinorVersion;

/*0AC*/ WORD                 NtBuildNumber;

/*0AE*/ WORD                 CmNtCSDVersion;

/*0B0*/ DWORD                PlatformId;

/*0B4*/ DWORD                Subsystem;

/*0B8*/ DWORD                MajorSubsystemVersion;

/*0BC*/ DWORD                MinorSubsystemVersion;

/*0C0*/ KAFFINITY            AffinityMask;

/*0C4*/ DWORD                ad0C4 [35];

/*150*/ PVOID                p150;

/*154*/ DWORD                ad154 [32];

/*1D4*/ HANDLE               Win32WindowStation;

/*1D8*/ DWORD                d1D8;

/*1DC*/ DWORD                d1DC;

/*1E0*/ PWORD                CSDVersion;

/*1E4*/ DWORD                d1E4;

/*1E8*/ }

        PEB,

     * PPEB,

    **PPPEB;

 

#define PEB_ \

        sizeof (PEB)

列表7-18.   进程环境块(PEB

 

实时访问系统中的对象(Accessing Live System Objects

前面的章节讲解了很多理论上的知识。我们现在需要一个实际的例子来演示对象管理机制,我为此编写了一个内核对象浏览器。该程序可以展示对象在分层结构中是如何排列的,以及如何获取这些对象的某些属性。不幸的是,ntoskrnl.exe没有导出该程序所需的几个关键结构和相应的函数。这意味着即使是内核驱动程序也无法访问它们,它们成了系统的个人私藏品了。从另一方面来看,第六章介绍了如何通过计算Windows 2000的符号文件来访问这些未导出的数据和代码,这里的对象浏览器正好可以测试一下这种理论是否真的可行。很不错,第六章的符号调用接口通过了测试,w2k_obj.exe示例程序的源代码位于本书CD\src\w2k_obj目录下。不过,该程序中最有趣的部分并不在w2k_obj.c中。第六章介绍的w2k_call.dll完成了大量的工作。因此,随后给出的示例代码均来自w2k_call.c

 

枚举对象目录项

你或许知道Windows 2000 DDK提供的一个小工具软件objdir.exe,它位于\ntddk\bin目录中。objdir.exe可通过为文档化的Native API函数NtQueryDirectoryObject()(由ntdll.dll导出)获取对象目录信息。已知相反的是,我的对象浏览器w2k_obj.exe将直接访问对象目录及其目录树中的叶子对象。这听起来很疯狂,但它确实做到了。最好的证据是可同时运行在Windows 2000Windows NT 4.0,它不依赖任何与特定版本相关的代码。不可否认,这两个版本中的对象结构稍微有些不同,但基本的模型还是一致的。提供一个可直接读取原始对象结构的程序而不是使用更高一级的API函数更能验证我们在前面提到的结构定义都是正确的。

 

在读取系统全局数据结构之前,最先要做的事情就是锁定它们。否则,系统可能会在另一个并发线程中改写这些数据,而我们的程序将可能会读取到无效数据或者到达一个空地址处。Windows 2000为其维护的众多内部数据项提供了大量的锁。我们面临的唯一问题是:这些锁通常都没有导出。尽管内核驱动程序可完成所有在用户模式下无法完成的工作,但它还是不能安全的访问这些未导出的数据结构。不过,第六章讨论过的扩展的内核调用接口可完成这一工作,该扩展接口实现在w2k_call.dll中,它通过从操作系统的符号文件中查找这些内部符号的地址来完成这一工作。该DLL导出了如下三个对象管理Thunks,以允许访问内核的对象目录:

1.         __ObpRootDirectoryMutex()返回ERESOURCE锁的地址,该锁用于同步访问对象目录。

 

2.         __ObpRootDirectoryObject()返回指向OBJECT_DIRECTORY结构的指针, 该结构代表对象目录的Root节点。

 

3.         __ObpTypeDirectoryObject()返回指向OBJECT_DIRECTORY结构的指针,该结构代表对象目录中的\ObjectTypes节点。

 

应用程序在使用指向内核对象的指针时,必须非常小心,尤其是在获取全局锁之后。如果全局锁不能被适当的释放,那么系统将可能进入死锁状态。

 

尽管root目录的锁叫做ObpRootDirectoryMutex,但严格来讲它并不是一个真正的Mutex。它实际上是一个ERESOURCE而不是KMUTEX。必须使用ExAcquireResourceExclusiveLite()ExAcquireResourceSharedLite()函数来获取这些锁。函数名中的Lite后缀非常重要----永远不要使用这两个函数的兄弟函数:ExAcquireResourceExclusive ()ExAcquireResourceShared ()来获取Windows 2000Windows NT 4.0