首页
论坛
课程
招聘

[系统底层] [讨论]句柄啊,3层表啊,ExpLookupHandleTableEntry啊...[已解决]

2008-1-8 21:43 9256

[系统底层] [讨论]句柄啊,3层表啊,ExpLookupHandleTableEntry啊...[已解决]

2008-1-8 21:43
9256
句柄这东西到了底层还真烦琐。HANDLE本来就是个void类型的4字节,保存指向object的指针.于是就有了

HANDLE_TABLE、HANDLE_TABLE_ENTRY、OBJECT_HEADER、 EXHANDLE


琢磨着这个EXHANDLE,它里面的Index保存着3层表索引。通过它,也就是EXHANDLE。Value 的后30位. 可以找到进程ID指向的object

关于这个3层表,“JIURL玩玩Win2k进程线程篇 HANDLE_TABLE”一文中也有比较详细的介绍,可惜是W2K滴, HANDLE_TABLE在XP中发生了变化,不过其中的第一个参数保存的内容仍然是指向HANDLE_TABLE_ENTRY,不过是要经过索引偏移后才能得到.



开始还准备用Windbg探索下这个3层表,发现困难重重 ---

准备搞下QQ进程中的HANDLE_TABLE,一张图接着一张图后,到 TableCode这里卡住了。不晓得具体怎么偏移才能继续搜索到下一层的表了。。。





就是这点破东西害的偶看WRK看了2天多。还是木有完全理解。哎,等以后脑子清醒了再看吧。标记之:

这个破函数偶现在是看不明白了。糊涂的很,关键还是对这个3层表没有理解正确。里面一会儿求余、一会儿整除的,搞糊涂了。要是哪位牛牛能给偶解释下就好了。

PHANDLE_TABLE_ENTRY
ExpLookupHandleTableEntry (
    IN PHANDLE_TABLE HandleTable,
    IN EXHANDLE tHandle
    )
{
// 一大堆局部变量
    ULONG_PTR i,j,k;
    ULONG_PTR CapturedTable;
    ULONG TableLevel;
    PHANDLE_TABLE_ENTRY Entry = NULL;
    EXHANDLE Handle;

    PUCHAR TableLevel1;
    PUCHAR TableLevel2;
    PUCHAR TableLevel3;

    ULONG_PTR MaxHandle;

    PAGED_CODE();

    Handle = tHandle;
    Handle.TagBits = 0;
    MaxHandle = *(volatile ULONG *) &HandleTable->NextHandleNeedingPool;

// 判断当前句柄是否有效
    if (Handle.Value >= MaxHandle) {
        return NULL;        
    }

//
// 得到当前的索引等级 -- 即 CapturedTable 的最后2位
// 而 (CapturedTable - TableLevel) 便是这个3层表的起始地址。
// 通过Handle.Value中的后30位保存的索引号,找到进程ID对应的HANDLE_TABLE_ENTRY
//
    CapturedTable = *(volatile ULONG_PTR *) &HandleTable->TableCode;
    TableLevel = (ULONG)(CapturedTable & 3);
    CapturedTable -= TableLevel;

// 有3种情况: 0、1、2
    switch (TableLevel) {
        
        case 0:        

            TableLevel1 = (PUCHAR) CapturedTable;

            // 就一层表。这层表中保存的就是一堆HANDLE_TABLE_ENTRY
            // 索引号*2 得到在其中的偏移量
            Entry = (PHANDLE_TABLE_ENTRY) &TableLevel1[Handle.Value * 2];

            break;
        
        case 1:
           
            TableLevel2 = (PUCHAR) CapturedTable;

            // 有2层表:上层 和 下层 [中层为空] 
            // 和2KB求余后,i保存的是在下层表中的索引
            i = Handle.Value % (2 * 1024);

            // 上层开始处偏移j后指向的是下层的开始处
            Handle.Value -= i;
            j = Handle.Value / ((2 * 1024) / 8);

            TableLevel1 = (PUCHAR) *(PHANDLE_TABLE_ENTRY *) &TableLevel2[j];
            Entry = (PHANDLE_TABLE_ENTRY) &TableLevel1[i * 2];

            break;
        
        case 2:

            TableLevel3 = (PUCHAR) CapturedTable;

            i = Handle.Value % (2 * 1024);

            Handle.Value -= i;

            k = Handle.Value / ((2 * 1024) / 8);

            j = k % (4 * 1024);

            k -= j;

            k = k / (1024 / 2);


            TableLevel2 = (PUCHAR) *(PHANDLE_TABLE_ENTRY *) &TableLevel3[k];
            TableLevel1 = (PUCHAR) *(PHANDLE_TABLE_ENTRY *) &TableLevel2[j];
            Entry = (PHANDLE_TABLE_ENTRY) &TableLevel1[i * 2];

            break;

        default :
            _assume (0);
    }

    return Entry;
}


[推荐]看雪企服平台,提供项目众包、渗透测试、安全分析、定制项目开发、APP等级保护等安全服务!

上传的附件:
最新回复 (6)
Rinrin 1 2008-1-8 23:01
2
0
楼主的WRK咋跟偶滴不一样?
PHANDLE_TABLE_ENTRY
ExpLookupHandleTableEntry (
IN PHANDLE_TABLE HandleTable,
IN EXHANDLE tHandle
)

/*++

Routine Description:

This routine looks up and returns the table entry for the
specified handle value.

Arguments:

HandleTable - Supplies the handle table being queried

tHandle - Supplies the handle value being queried

Return Value:

Returns a pointer to the corresponding table entry for the input
handle. Or NULL if the handle value is invalid (i.e., too large
for the tables current allocation.

--*/

{
ULONG_PTR i,j,k;
ULONG_PTR CapturedTable;
ULONG TableLevel;
PHANDLE_TABLE_ENTRY Entry = NULL;
EXHANDLE Handle;

PUCHAR TableLevel1;
PUCHAR TableLevel2;
PUCHAR TableLevel3;

ULONG_PTR MaxHandle;

PAGED_CODE();


//
// Extract the handle index
//
Handle = tHandle;

Handle.TagBits = 0;

MaxHandle = *(volatile ULONG *) &HandleTable->NextHandleNeedingPool;

//
// See if this can be a valid handle given the table levels.
//
if (Handle.Value >= MaxHandle) {
return NULL;
}

//
// Now fetch the table address and level bits. We must preserve the
// ordering here.
//
CapturedTable = *(volatile ULONG_PTR *) &HandleTable->TableCode;

//
// we need to capture the current table. This routine is lock free
// so another thread may change the table at HandleTable->TableCode
//

TableLevel = (ULONG)(CapturedTable & LEVEL_CODE_MASK);
CapturedTable = CapturedTable - TableLevel;

//
// The lookup code depends on number of levels we have
//

switch (TableLevel) {

case 0:

//
// We have a simple index into the array, for a single level
// handle table
//


TableLevel1 = (PUCHAR) CapturedTable;

//
// The index for this level is already scaled by a factor of 4. Take advantage of this
//

Entry = (PHANDLE_TABLE_ENTRY) &TableLevel1[Handle.Value *
(sizeof (HANDLE_TABLE_ENTRY) / HANDLE_VALUE_INC)];

break;

case 1:

//
// we have a 2 level handle table. We need to get the upper index
// and lower index into the array
//


TableLevel2 = (PUCHAR) CapturedTable;

i = Handle.Value % (LOWLEVEL_COUNT * HANDLE_VALUE_INC);

Handle.Value -= i;
j = Handle.Value / ((LOWLEVEL_COUNT * HANDLE_VALUE_INC) / sizeof (PHANDLE_TABLE_ENTRY));

TableLevel1 = (PUCHAR) *(PHANDLE_TABLE_ENTRY *) &TableLevel2[j];
Entry = (PHANDLE_TABLE_ENTRY) &TableLevel1[i * (sizeof (HANDLE_TABLE_ENTRY) / HANDLE_VALUE_INC)];

break;

case 2:

//
// We have here a three level handle table.
//


TableLevel3 = (PUCHAR) CapturedTable;

i = Handle.Value % (LOWLEVEL_COUNT * HANDLE_VALUE_INC);

Handle.Value -= i;

k = Handle.Value / ((LOWLEVEL_COUNT * HANDLE_VALUE_INC) / sizeof (PHANDLE_TABLE_ENTRY));

j = k % (MIDLEVEL_COUNT * sizeof (PHANDLE_TABLE_ENTRY));

k -= j;

k /= MIDLEVEL_COUNT;


TableLevel2 = (PUCHAR) *(PHANDLE_TABLE_ENTRY *) &TableLevel3[k];
TableLevel1 = (PUCHAR) *(PHANDLE_TABLE_ENTRY *) &TableLevel2[j];
Entry = (PHANDLE_TABLE_ENTRY) &TableLevel1[i * (sizeof (HANDLE_TABLE_ENTRY) / HANDLE_VALUE_INC)];

break;

default :
_assume (0);
}

return Entry;
}
sudami 25 2008-1-9 08:19
3
0
呵呵。是一样的。

偶把那些全局变量直接换成数字了,看着方便。

知道的冒泡啊~~
笨笨雄 14 2008-1-9 11:17
4
0
自己尝试做4G索引,再看看MS是怎么做,然后大概就明白了
whtyy 1 2008-1-9 12:11
5
0
我以前得一点笔记,你看有没帮助

wrk1.2中
ExpLookupHandleTableEntry的内部流程
1) 取 Handle(EXHANDLE类型) 值为tHandle,并将TagBit(低两位)置0
2) 取 HandleTable->NextHandleNeedingPool为MaxHandle ,
   如果 tHandle大于等于MaxHandle,则返回NULL,查询失败
   (由此可见, NextHandleNeedingPool 应该是当前句柄表的最大句柄值+1
    或者说是下一个可用的句柄值)
3) 取 CapturedTable(ULONG_PTR类型)为HandleTable->TableCode
   取 TableLevel(ULONG)为(CapturedTable & LEVEL_CODE_MASK);
      (LEVEL_CODE_MASK=3,即由HandleTable->TableCode的低2位来指定句柄表的级数)
   CapturedTable 减去 TableLevel (即CapturedTable的低2位置0)
4) 根据 TableLevel 来进行不同方式的查找

    令:
    PCHAR TableLevel1; 最低层的表指针
    PCHAR TableLevel2; 中间层的表指针
    PCHAR TableLevel3; 最上层的表指针
    ULONG_PTR i; 最低层的表索引
    ULONG_PTR j; 中间层的表索引
    ULONG_PTR k; 最上层的表索引
    PHANDLE_TABLE_ENTRY Entry 最后找到的句柄项目的指针

a) TableLeve = 0    句柄表只有1级,此时CapturedTable只是一个大小为512(4K/8=512)
     的HANDLE_TABLE_ENTRY数组,Handle的高30位即是索引.
     (当然,实际上因为一级表为512项,所以其实只有2~10 9位为有效索引,其中11~31位在
     第二步中被检查过,必为0).

     由于每个HANDLE_TABLE_ENTRY大小为8,所以对应的Entry相对于表起始地址的偏移
     为 Handle.Value>>2 * 8
        TableLevel1 = CapturedTable;
        Entry = TableLevel1 + (Handle.Value>>2) * 8
              = TableLevel1 + Handle.Index * 8
              = TableLevel1 + Handle.Value * 2 (因为第1步中已经将低2位置0了)

    wrk 1.2中代码如下

      Entry = (PHANDLE_TABLE_ENTRY) &TableLevel1[Handle.Value *
                               (sizeof (HANDLE_TABLE_ENTRY) / HANDLE_VALUE_INC)];

      其中HANDLE_VALUE_INC在EXHANDLE结构中定义,值是4

b) TableLeve = 1   句柄表有2级,
     第1层存储的是第2层表的指针(大小为4字节).
     第2层存储的是HANDLE_TABLE_ENTRY(大小为8个字节)
     
     句柄的2~10位为最底层表(第2层)的索引,11~N位为中间层表(第1层)索引
     (注:N的值从3层句柄表的情况看,应该为)

     wrk 1.2中的代码及分析如下
     +++++++++++++++++++++++++++++++++++++++++++++++
     i = Handle.Value % (LOWLEVEL_COUNT * HANDLE_VALUE_INC);
       /*
       = Handle.Value % 0x800
       = Handle & 0x7FF
       等效作用是取低11位
       */

     Handle.Value -= i; 低11位置0

     j = Handle.Value / ((LOWLEVEL_COUNT * HANDLE_VALUE_INC) / sizeof (PHANDLE_TABLE_ENTRY));
       /*
       = Handle.Value / (0x800 / 4)
       = (Handle.Value >> 11) * 4
       等效如下代码,实际上是取11~N为位为索引,并乘以4,得到中间表的表中偏移
       */

     TableLevel2 = (PUCHAR) CapturedTable;
     TableLevel1 =  *(PUCHAR)(TableLevel2 + j);
     Entry = TableLevel1+ (i * (sizeof (HANDLE_TABLE_ENTRY) / HANDLE_VALUE_INC));
           /*
           = TableLevel1+ (i*2)
           = TableLevel1+ ((i>>4) * 8)
           等效于最低层表索引(2~10位)乘以sizeof(HANDLE_TABLE_ENTRY),得到表中偏移.
           */
     ------------------------------------------------

c) TableLeve = 2  句柄表有3层
     第1层存储的是第2层表的指针(大小为4字节).
     第2层存储的是第3层表的指针(大小为4字节).
     第3层存储的是HANDLE_TABLE_ENTRY(大小为8个字节)

     句柄的2~10位为最底层表(第3层)的索引,11~20位为中间层表(第2层)索引,
     20~N位为第一层索引(因为第1层最有4K/4个元素,索引应该也为10位,故推测
     N实际上应该为30)
     
     wrk 1.2中的代码及分析如下
     +++++++++++++++++++++++++++++++++++++++++++++++
     i = Handle.Value  % (LOWLEVEL_COUNT * HANDLE_VALUE_INC);

     Handle.Value -= i; 低11位清0

     k = Handle.Value / ((LOWLEVEL_COUNT * HANDLE_VALUE_INC) / sizeof (PHANDLE_TABLE_ENTRY));
       /*
       = Handle.Value / (0x800 / 4)
       = (Handle.Value >> 11) * 4
       k取句柄的11~N为位,并乘以4
       */

     j = k % (MIDLEVEL_COUNT * sizeof (PHANDLE_TABLE_ENTRY));
       /*
       = k % (4K/4 * 4)
       = k % 0x1000
       = k & 0xFFF
       取k的低12位,实际上就是:句柄的11~20位为索引 * 4
       */

     k -= j; k的低12位清0

     k /= MIDLEVEL_COUNT;
       /*
       = k / (4k/4)
       = k / 0x1000
       = k >> 10
       取k的高10~N位,实际上就是句柄的21~N位为索引再乘以4
       */

     TableLevel3 = (PUCHAR) CapturedTable;
     TableLevel2 = (PUCHAR) *(PHANDLE_TABLE_ENTRY *) &TableLevel3[k];
     TableLevel1 = (PUCHAR) *(PHANDLE_TABLE_ENTRY *) &TableLevel2[j];
     Entry = (PHANDLE_TABLE_ENTRY) &TableLevel1[i * (sizeof (HANDLE_TABLE_ENTRY) / HANDLE_VALUE_INC)];
     ------------------------------------------------
sudami 25 2008-1-9 16:31
6
0
呵呵,谢谢啊。偶已经彻底明白了~

http://www.debugman.com/read.php?tid=830
fengyunabc 1 2018-8-27 00:49
7
0
回帖内容很经典,谢谢。
游客
登录 | 注册 方可回帖
返回