RtlDeleteElementGenericTable小记

实验室的产品需要添加一个驱动,其中用到了RTL_GENERIC_TABLE,也就不可避免地用到了RtlDeleteElementGenericTable。

RTL_GENERIC_TABLE默认实现是伸展树,RtlDeleteElementGenericTable主要执行三个步骤:

1. 查找要删除的element的位置。

2. 使用RtlDelete移除element,RtlDelete会调用RtlSplay调整树结构

3. 调用FreeRoutine释放element内存。

RtlDeleteElementGenericTable实现在NtosKrnl.exe中,将其反编译,得到的代码大致是:

uint RtlDeleteElementGenericTable(undefined4 *param_1,int param_2)
{
  int iVar1;
  int *piVar2;
  int iVar3;
  uint uVar4;
  undefined4 uVar5;
  
                    /* 0x1534fa  1067  RtlDeleteElementGenericTable */
  uVar4 = FUN_0055345c(param_2,¶m_2);
  iVar3 = param_2;
  if ((uVar4 == 0) || (uVar4 != 1)) {
    uVar4 = uVar4 & 0xffffff00;
  }
  else {
    uVar5 = RtlDelete(param_2);
    *param_1 = uVar5;
    iVar1 = *(int *)(iVar3 + 0xc);
    piVar2 = *(int **)(iVar3 + 0x10);
    *piVar2 = iVar1;
    *(int **)(iVar1 + 4) = piVar2;
    param_1[5] = param_1[5] + -1;
    param_1[4] = 0;
    *(undefined4 **)(param_1 + 3) = param_1 + 1;
    uVar5 = (*(code *)param_1[8])(param_1,iVar3);
    uVar4 = CONCAT31((int3)((uint)uVar5 >> 8),1);
  }
  return uVar4;
}

其中param_1就是table,param_2指向要删除的element。

查找要删除的element:

uVar4 = FUN_0055345c(param_2,¶m_2);

删除element:

uVar5 = RtlDelete(param_2);

调用初始化table时注册的FreeRoutine释放内存:

uVar5 = (*(code *)param_1[8])(param_1,iVar3);

FreeRoutine的原型是:

VOID
(*PRTL_GENERIC_FREE_ROUTINE) (
    __in struct _RTL_GENERIC_TABLE  *Table,
    __in PVOID  Buffer
    );

FreeRoutine的实现通常很简单,直接释放内存即可。其中Buffer参数是存储element的内存块,但通过windbg等工具查看内存可以发现Buffer并不是直接指向我们插入到table中的element,它指向table中的node。


欢迎关注微信公众号【CPP笔记】

你可能感兴趣的:(Windows,驱动程序,windows)