RING0获取线程的TDB.
作者:陆麟
转载请征得作者同意.
2000.10.13


最近有个朋友问我如何从RING0获取TDB.
TDB是个KERNEL32数据结构,而RING0有的是THCB,TDBX.THCB是VMM的数据结构,而TDBX是VWIN32的数据结构.现在,我就针对WIN98英文版对此进行剖析.
我们通常可以从RING0获得的在MS的文档里称为THREAD HANDLE.其实,我们获得的是一个THCB指针.THCB乃是一个半公开的数据结构.为什么这么说呢?MS的95/98DDK里公开了部分的THCB的数据结构.如下:
struct tcb_s {
    ULONG   TCB_Flags;  /* Thread status flags */
    ULONG   TCB_Reserved1; /* Used internally by VMM */
    ULONG   TCB_Reserved2; /* Used internally by VMM */
    ULONG   TCB_Signature;
    ULONG   TCB_ClientPtr; /* Client registers of thread */
    ULONG   TCB_VMHandle; /* VM that thread is part of */
    USHORT  TCB_ThreadId; /* Unique Thread ID */
    USHORT  TCB_PMLockOrigSS;     /* Original SS:ESP before lock stack */
    ULONG   TCB_PMLockOrigESP;
    ULONG   TCB_PMLockOrigEIP;     /* Original CS:EIP before lock stack */
    ULONG   TCB_PMLockStackCount;
    USHORT  TCB_PMLockOrigCS;
    USHORT  TCB_PMPSPSelector;
    ULONG   TCB_ThreadType; /* dword passed to VMMCreateThread */
    USHORT  TCB_pad1;  /* reusable; for dword align */
    UCHAR   TCB_pad2;  /* reusable; for dword align */
    UCHAR   TCB_extErrLocus;     /* extended error Locus */
    USHORT  TCB_extErr;  /* extended error Code */
    UCHAR   TCB_extErrAction;     /*     "   "   Action */
    UCHAR   TCB_extErrClass;     /*     "   "   Class */
    ULONG   TCB_extErrPtr; /* "   pointer */

};
显然,这里并没有包含95/98内的另外几个核心数据结构.为了了解VWIN32的线程数据结构,我们不得不对THCB继续探索下去.
VWIN32.VXD在线程被创建时同时创建了TDBX数据结构.用于对线程的管理.但是,VWIN32并没有在自己内部维护一个线程数据链表,取而代之的是在THCB偏移84H处填写了一个数据结构的地址.
现在取出THCB+84H处的DWORD,我们得到一个指针.但是这个指针并不是一个指向TDBX的指针,在这个指针所指向的数据结构的偏移4处,才是我们所感兴趣的TDBX结构指针.这样,我们的TDBX就得到了.我的示例代码如下:

MOV ESI,THCB
MOV EAX,[ESI+84]
ADD EAX,4
MOV EAX,[EAX];;至此,TDBX指针有了

TDBX的偏移4处则存储KERNEL32.DLL维护的TDB数据结构指针.现在,THCB,TDBX,TDB就完全从RING0串联起来了.
而TDBX/TDB的具体结构,大家可以看本主页的相关文章.

现在,如果要获取当前线程的TDB,我们更是有取巧的办法.98英文版的KERNEL32.DLL总在[BFFC9CD8]处存储当前TDB的指针.所以,
MOV EAX,[BFFC9CD8]
就可以获得当前线程的TDB.

鼓掌,收工.:)