设为首页 加入收藏

TOP

12.1 识别类和类之间的关系(10)
2013-10-07 14:31:18 来源: 作者: 【 】 浏览:59
Tags:12.1 识别 类和 之间 关系

12.1 识别类和类之间的关系(10)

指令“call dword ptr [eax+8]”揭示出虚表中至少有三个元素!接下来分析虚表第三项是什么内容。

  1. .rdata:0040C0D0 vTable_40C0D0 dd offset sub_4011C0 ; 虚表偏移0处,也就是虚表的第一项  
  2. .rdata:0040C0D4 off_40C0D4 dd offset sub_401140 ; 虚表偏移4处,也就是虚表的第二项  
  3. ; 虚表偏移8处,也就是虚表的第三项,现在可以确定GetCChinese是虚表的元素之一  
  4. .rdata:0040C0D8 pfnGetCChinese dd offset GetCChinese 

接着往下看:
  1. .text:00401145     push eax ; 向printf传入GetCChinese的返回值,是个字符串首地址  
  2. .text:00401146     push offset Format ; "%s::ShowSpeak()\r\n"  
  3. .text:0040114B     call _printf  
  4. .text:00401150     add esp, 8   ; 调用printf显示字符串,并平衡参数  
  5. .text:00401153     retn  
  6. .text:00401153 sub_401140 endp 

这个函数的作用是调用虚表第三项元素,得到字符串,并将字符串格式化输出。由于是按虚表调用的,因此会形成多态性。顺便把这个函数的名称修改为ShowShtring,对应的虚表内的函数指针off_40C0D4修改为pfnShowShtring,修改后虚表结构如下所示:
  1. .rdata:0040C0D0 vTable_40C0D0 dd offset sub_4011C0  
  2. .rdata:0040C0D4 pfnShowShtring dd offset ShowShtring  
  3. .rdata:0040C0D8 pfnGetCChinese dd offset GetCChinese 

我们回到main函数处,继续分析:
  1. .text:00401103     test esi, esi  
  2. .text:00401105     jz  short loc_40110F     ; 检查堆指针,不为0则往下执行  
  3. .text:00401107     mov edx, [esi]       ; edx得到虚表  
  4. .text:00401109     push 1           ; 传入参数  
  5. .text:0040110B     mov ecx, esi     ; 传递this指针  
  6. .text:0040110D     call dword ptr [edx]     ; 调用虚表中的第一项  
  7. .text:0040110F  ; 从00401105处跳转到此,其上没有jmp,所以这里是个单分支结构  
  8. .text:0040110F loc_40110F:  
  9. .text:0040110F     mov ecx, [esp+14h+var_C] ; 函数退出,恢复环境,还原SEH  
  10. .text:00401113     pop esi  
  11. .text:00401114     mov large fs:0, ecx  
  12. .text:0040111B     add esp, 10h  
  13. .text:0040111E     retn  
  14. .text:0040111E _main endp 

call dword ptr [edx]命令调用虚表的第一项。在详细分析虚表的第一项之前,我们体验一下IDA中的交叉参考功能,一次性定位所有的构造函数和析构函数,先定位到虚表vTable_40C0D0处,然后右击,如图12-4所示。

在右键菜单中选择“Chart of xrefs to”,得到所有直接引用这个地址的位置,如图12-5所示。

可以看到,除了main函数访问了虚表vTable_40C0D0之外,sub_4011E0也访问了虚表vTable_40C0D0。通过前面的分析可知,是因为main函数中内联的构造函数存在写入虚表的操作,从而导致vTable_40C0D0被访问到。由于存在虚表,就算类中没有定义析构函数,编译器也会产生默认的析构函数,因此,毫无疑问另一个访问虚表的函数sub_4011E0就是析构函数。交叉参考这个功能很好用,如果你发现了一个父类的构造函数,想知道这个父类有多少个派生类,也能利用这个功能快速定位。

 
图12-4 交叉参考
 
图12-5 IDA自动生成的交叉参考图示
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇12.1 识别类和类之间的关系(11) 下一篇12.1 识别类和类之间的关系(9)

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: