在对基于COM的应用程序进行调试时,线程的套间类型,往往是我们必须知道的信息。如果应用程序是基于.Net的,那么问题很容易解决。我们可以加载SOS扩展库,然后调用!comstate命令,即可列出所有线程的套间类型。但是如果应用程序不是基于.Net的,SOS扩展库将无法使用。这时如何获取线程的套间类型呢?
要想获取套间类型信息,必须知道这个信息存在什么地方。答案是线程的TEB里。查看TEB结构,可以看到在其偏移0xf80处,有一个字段ReservedForOle。如下所示:
0:000> dt ntdll!_TEB
……
+0xf7c ReservedForPerf : Ptr32 Void
+0xf80 ReservedForOle : Ptr32 Void
+0xf84 WaitingOnLoaderLock : Uint4B
……
当一个线程与一个套间关联上后,这个字段会保存一个指针,指向一个与套间相关的线程局部存储的数据结构。在这个数据结构的0xc偏移处,存放的正是套间的类型信息。
根据以上知识,我们可以如下获取套间类型:
0:000> r $teb
$teb=7ffdd000
0:000> dd 7ffdd000+f80 l1
7ffddf80 0016f178
0:000> dd 16f178+c l1
0016f184 0000008b
0:000> ? 8b & 80
Evaluate expression: 128 = 00000080
以上四步,第一步是得到线程TEB地址,第二步获取ReservedForOle 指针值,第三步获取套间类型字段。第四步把该字段值和0x80相与,如果不为0,则是STA,否则为MTA。上例结果为128,所以当前线程为STA。然后可以切换到其他线程,重复同样的操作,得到套间类型。
有一点值得注意的是,如果线程没有与套间关联,则第二步获取的ReservedForOle 指针值为空,也就无法获取套间类型。
上述步骤可以归结为一条命令,应用于当前进程的所有线程,并打印结果,如下:
~*e
.if ( poi(@$teb+f80) == 0) { .echo Unknown } .else { .if (
poi(poi(@$teb+f80)+c) & 80 ) { .echo STA } .else { .echo MTA } }