htmlnbsp:5.4.4  RtlGetElementGenericTable

作者: [美]Eldad Eilam 著 韩琪 等译 出处:电子工业出版社博文视点

5.4.4  RtlGetElementGenericTable

在generic table API中有 3个看上去好像是用来查找和检索元素它们是RtlGetElementGenericTable、RtlEnumerateGenericTable和RtlLookupElementGenericTable仅根据它们我们就可以轻松猜出这 3个是干什么最容易猜是RtlEnumerateGenericTable它显然是枚举表中部分或者全部元素接下来问题是:RtlGetElementGenericTable和RtlLookupElementGenericTable的间有什么区别?不看代码是不可能回答这个问题不过如果非要让我猜我会猜RtlGetElement GenericTable具有种直接访问元素能力(可能是用索引来访问)而RtlLookupElementGenericTable可能要在表中搜索正确元素

如果我猜得没错在这两个中可能RtlGetElementGenericTable比较简单列表5.2给出了RtlGetElementGenericTable完整反汇编代码在继续读我分析的前你不妨试着自己分析下这些代码

498)this.style.width=498;" border=0>




这段代码执行“EAX = EAX + 12”然后无条件跳转到ntdll.7C96255B如果你回到列表5.2你会看到ntdll.7C96255B就在该结尾处所以上面代码就是给主调返回“EAX+12”回想早些时候EAX是从table数据结构偏移地址+C处加载并且在解读RtlInitializeGenericTable时我们假定偏移地址+4、+8和+C处都是指向同种 3指针数据结构指针(它们都被化为指向偏移地址+4处指针)在这里这些指针中个增加了12后返回给主调这为我们理解GenericTable提供了很多线索我们来逐个分析下:

, 你知道根数据结构中从偏移地址+4处开始有 3个指针;

, 你知道这 3个指针每个都是指向另外个 3指针组化时它们都是指向它们自己但你可以放心地认为在向table填充元素时情况就变了;

, 你知道RtlGetElementGenericTable给主调返回是这些指针中但是在将其值加上12后返回注意12恰好是 3个指针加起来长度;

, 你已经知道RtlGetElementGenericTable接收两个参数个参数是指向table数据结构指针第 2个参数是table索引你可以放心地假定这个返回是这种元素

综合上述几点你可以推知RtlGetElementGenericTable返回指向个元素指针加上12只是为了跳过元素头部而直接指向元素数据这个头部看上去很像是另个 3指针数据结构就像根数据结构偏移地址+4处那样另外这 3个中个都应该指向其他带有 3指针头部向才有意义就像这个此外偏移地址+10是缓存Cache元素(cached element——由第 3个指针指向元素(在偏移地址+C处))索引区别是偏移地址+C是指向内存单元地址而偏移地址+10是table索引等价于个元素编号

对我来说这是个令人激动逆向过程——我们点地收集证据然后把这些证据整合起来先形成个带有主观猜测解释然后逐渐成为对代码完整理解对于这项逆向任务我们无疑已经在最重要难题上——generic table数据结构上取得了突破性进展

逻辑和结构

我们总是在不经意间忽略掉个关键问题:这个结构是怎样?当然你可以将那些条件跳转语句和无条件跳转语句全部当作goto指令来处理但用这种思路方法只能帮助你理解相对简单代码流程方面如果段代码中有太多跳转语句而使得你很难追踪到所有这些跳转会怎样呢?我想你现在应该考虑下代码“逻辑和结构”问题了你可以从试着按照逻辑关系摆放这些条件跳转语句和无条件跳转语句开始记住了你正在逆向汇编语言代码是用编译器生成而源代码可能是用C语言写极有可能这个逻辑完全是用-语句组织代码生成你怎样才能重构出它原来样子呢?

让我们从代码列表5.2中个有趣条件跳转语句——跳转到ntdll.7C962554那条JE语句开始吧(我忽略了前面两个跳转到ntdll.7C962559处条件跳转语句这两条语句我们前面已经讨论过了)假设是用高级语言写你会使用什么样语句实现跳过这么多行代码条件跳转呢?很简单汇编语言代码中条件跳转语句测试条件定和源代码(即高级语言代码)中语句中判断条件刚好相反这是处理器需要知道在什么情况下要跳过那些代码;高级语言视角则完全区别我们需要考虑是满足什么条件才会执行某个条件块这么说来测试是否满足ESI等于EBX源代码必定是“ (ESI != EBX)”而且紧接其后对花括号(curly braces)中有大段代码JE语句跳转目标地址就是该条件块结束的后代码地址

认识到这点非常重要按照这理论我们可以断定在JE语句和JE语句跳转目标地址的间所有代码都属于同个条件块因此在这个条件块中出现任何其他条件语句都可以当作嵌套逻辑(nested logic)来对待
我们把这个逻辑分析思路方法再扩展该JE指令的后紧接着是条条件跳转指令它仍然是测试ESI和EBX这两个寄存器值:如果“ESI <= EBX”则跳转到ntdll.7C96252B处我们还是假设高级语言中测试条件必然和汇编语言中测试条件相反(附录A中详细讨论了什么时候刚好相反什么时候不是)这就是说源代码中原来测试条件必定是(ESI > EBX)如果不满足条件“ESI > EBX”则跳过该条件块

需要强调是对于这个特殊跳转指令——该无条件跳转指令JMP就出现在ntdll.7C96252B的前这就是说:如果上面条件块被执行了ntdll.7C96252B后边这段代码就不能执行这就意味着在高级语言中只有条件块被跳过了才会执行ntdll.7C96252B后面这段代码为什么会这样?如果你好好想想就会发现这不就是高级语言中再常见不过设计构造——-语句吗?其中起始位置是ntdll.7C96252B这就是为什么在块的后有个无条件跳转语句我们只能让两个块中个执行而不是两个都执行


无论在什么情况下只要你看到跳过个以指向更高地址(forward-poing)无条件跳转JMP结尾代码块条件跳转你都应该立即意识到这可能是-语句块被跳过代码块就是而无条件跳转JMP后面就是这句无条件JMP跳转向目标地址就是语句块结束地方




你可以在附录A中找到更多有关编译器生成逻辑结构信息

我们继续分析在研究ntdll.7C96252B处代码的前所看代码块要知道我们刚比较了ESI(它是偏移地址+10索引)I和EBX(它显然就是我们想要获得元素索引)接着有两个条件转移指令:第个条件转移指令(我们已经研究过了)在两个操作数相等情况下发生跳转;第 2个条件跳转指令在“ESI <= EBX”情况下跳转到ntdll.7C96252B我们等会再来讨论ntdll.7C96252B处这段条件代码你应该意识到这两个条件转移指令的后面代码只有满足ESI>EBX时才会执行我们已经测试了“ESI EBX”和“ESI < EBX”并给出了它们跳转位置这才是最重要

当上面两个条件转移指令条件都没有执行时代码会将ESI中值拷贝到EDX寄存器中然后将EDX中值右移 2进制移位操作是实现操作数乘以或除以2指数次方比较常用思路方法将整数x左移n位可以得到“x*2n”;右移n位则得到“x/2n”在这种情况下将EDX右移1意味着EDX/21或EDX/2要获得更多有关怎样辨认算术代码信息可参考附录B

接下来是条将EDX寄存器(这时EDX中值是ESI/2)和EBX寄存器(EBX中值是我们要找元素索引加1)进行比较语句并且如果EBX小于或等于EDX则跳转到ntdll.7c96251B如假定两个操作数EBX和EDX都是无符号数也就是说表索引是用无符号整型数来表示因此你完全不必担心它安全问题我们先跳过这个跳转转移指令就当这个条件转移根本没有发生过继续看下面代码

接下来指令将ESI减去EBX并将结果存放在ESI中但是再往下指令可能会让有些人摸不着头脑你可以看到这条减法指令后面是句JE指令(如果相等则跳转)实际上比较指令和减法指令是会事儿都是做了减法运算只不过比较指令不保存减法运算结果只保留了对标志位影响因此这条JE指令执行跳转条件是:如果减法运算作的前“EBX ESI”或者减法运算后“ESI 0”(这两个条件实际上是回事儿只是看上去区别而已)注意这暴露了代码中个冗余操作——你在前边已经比较过EBX和ESI寄存器并在EBX等于ESI情况了退出此(还记得跳转到ntdll.7C962554代码吗?)所以这里ESI是不可能等于0我想写这段代码定有充足理由应对“紧接着这个检测的后代码不会在“ESI EBX”情况下被执行”两处检测让我们来看看这到底是如何回事儿

搜索循环1

现在你已经分析完了从ntdll.7C962501开始到ntdll.7c962511结束这段代码了接下来代码看起来好像是某种类型循环让我们起看下这些代码并试着分析它功能





  • 篇文章: 5.4.3 RtlIsGenericTableEmpty

  • 篇文章: 5.4.5 RtlInsertElementGenericTable
  • Tags:  nbspnbsp nbsp什么意思 nbsp是什么意思 htmlnbsp

    延伸阅读

    最新评论

    发表评论