C 中通过溢出覆盖虚函数指针列表执行代码

上传人:20****03 文档编号:178994009 上传时间:2021-04-06 格式:DOC 页数:12 大小:40.50KB
返回 下载 相关 举报
C 中通过溢出覆盖虚函数指针列表执行代码_第1页
第1页 / 共12页
C 中通过溢出覆盖虚函数指针列表执行代码_第2页
第2页 / 共12页
C 中通过溢出覆盖虚函数指针列表执行代码_第3页
第3页 / 共12页
C 中通过溢出覆盖虚函数指针列表执行代码_第4页
第4页 / 共12页
C 中通过溢出覆盖虚函数指针列表执行代码_第5页
第5页 / 共12页
点击查看更多>>
资源描述

《C 中通过溢出覆盖虚函数指针列表执行代码》由会员分享,可在线阅读,更多相关《C 中通过溢出覆盖虚函数指针列表执行代码(12页珍藏版)》请在金锄头文库上搜索。

1、C+中通过溢出覆盖虚函数指针列表执行代码目录: 1. C+中虚函数的静态联编和动态联编 2. VC中对象的空间组织和溢出试验 3. GCC中对象的空间组织和溢出试验 4. 参考 C+中虚函数的静态联编和动态联编 C+中的一大法宝就是虚函数,简单来说就是加virtual关键字定义的函数。 其特性就是支持动态联编。现在C+开发的大型软件中几乎已经离不开虚函数的 使用,一个典型的例子就是虚函数是MFC的基石之一。 这里有两个概念需要先解释: 静态联编:通俗点来讲就是程序编译时确定调用目标的地址。 动态联编:程序运行阶段确定调用目标的地址。 在C+中通常的函数调用都是静态联编,但如果定义函数时加了vi

2、rtual关键 字,并且在调用函数时是通过指针或引用调用,那么此时就是采用动态联编。 一个简单例子:/ test.cpp#includeclass ClassApublic: int num1; ClassA() num1=0xffff; ; virtual void test1(void); virtual void test2(void);ClassA objA,* pobjA;int main(void) pobjA=&objA; objA.test1(); objA.test2(); pobjA-test1(); pobjA-test2(); return 0;使用VC编译:开一个命令

3、行直接在命令行调用cl来编译: (如果你安装vc时没有选择注册环境变量,那么先在命令行运行VC目录下binVCVARS32.BAT )cl test.cpp /Fa产生test.asm中间汇编代码接下来就看看asm里有什么玄虚,分析起来有点长,要有耐心 !我们来看看:数据定义:_BSS SEGMENT?objA3VClassAA DQ 01H DUP (?) ;objA 64位?pobjA3PAVClassAA DD 01H DUP (?) ;pobjA 一个地址32位_BSS ENDS看到objA为64位,里边存放了哪些内容呢? 接着看看构造函数:_this$ = -4?0ClassAQAE

4、XZ PROC NEAR ; ClassA:ClassA() 定义了一个变量 _this ?!; File test.cpp; Line 6 push ebp mov ebp, esp push ecx mov DWORD PTR _this$ebp, ecx ; ecx 赋值给 _this ? 不明白? mov eax, DWORD PTR _this$ebp mov DWORD PTR eax, OFFSET FLAT:?_7ClassA6B ; ClassA:vftable; 前面的部分都是编译器加的东东,我们的赋值在这里 mov ecx, DWORD PTR _this$ebp mov

5、 DWORD PTR ecx+4, 65535 ;0xffff num1=0xffff; 看来 _this+4就是num1的地址 mov eax, DWORD PTR _this$ebp mov esp, ebp pop ebp ret 0?0ClassAQAEXZ ENDP那个_this和mov DWORD PTR _this$ebp, ecx 让人比较郁闷了吧,不急看看何处调用的构造函数:_$E9 PROC NEAR; File test.cpp; Line 10 push ebp mov ebp, esp mov ecx, OFFSET FLAT:?objA3VClassAA call

6、?0ClassAQAEXZ ;call ClassA:ClassA() pop ebp ret 0_$E9 ENDP看,ecx指向objA的地址,通过赋值,那个_this就是objA的开始地址,其实CLASS中的非静态方法编译器编译时都会自动添加一个this变量,并且在函数开始处把ecx赋值给他,指向调用该方法的对象的地址 。那么构造函数里的这两行又是干什么呢? mov eax, DWORD PTR _this$ebp mov DWORD PTR eax, OFFSET FLAT:?_7ClassA6B ; ClassA:vftable我们已经知道_this保存的为对象地址: &objA。 那

7、么 eax = &objA接着就相当于 ( * eax ) = OFFSET FLAT:?_7ClassA6B来看看 ?_7ClassA6B 是哪个道上混的:CONST SEGMENT?_7ClassA6B DD FLAT:?test1ClassAUAEXXZ ; ClassA:vftable DD FLAT:?test2ClassAUAEXXZCONST ENDS看来这里存放的就是test1(),test2()函数的入口地址 ! 那么这个赋值: mov DWORD PTR eax, OFFSET FLAT:?_7ClassA6B ; ClassA:vftable就是在对象的起始地址填入这么一

8、个地址列表的地址。好了,至此我们已经看到了objA的构造了:| 低地址 |+-+ - objA的起始地址 &objA|pvftable|+-+-+| num1 | num1变量的空间 |+-+ - objA的结束地址 +-+-+ 地址表 vftable| 高地址 | |test1()的地址 | +-+ |test2()的地址 | +-+来看看main函数:_main PROC NEAR; Line 13 push ebp mov ebp, esp; Line 14 mov DWORD PTR ?pobjA3PAVClassAA, OFFSET FLAT:?objA3VClassAA ; pob

9、jA = &objA; Line 15 mov ecx, OFFSET FLAT:?objA3VClassAA ; ecx = this指针 ; 指向调用者的地址 call ?test1ClassAUAEXXZ ; objA.test1() ; objA.test1()直接调用,已经确定了地址; Line 16 mov ecx, OFFSET FLAT:?objA3VClassAA call ?test2ClassAUAEXXZ ; objA.test2(); Line 17 mov eax, DWORD PTR ?pobjA3PAVClassAA ; pobjA mov edx, DWORD

10、 PTR eax ; edx = vftable mov ecx, DWORD PTR ?pobjA3PAVClassAA ; pobjA call DWORD PTR edx ; ; call vftable0 即 pobjA-test1() 看地址是动态查找的 ; ) ; Line 18 mov eax, DWORD PTR ?pobjA3PAVClassAA ; pobjA mov edx, DWORD PTR eax mov ecx, DWORD PTR ?pobjA3PAVClassAA ; pobjA call DWORD PTR edx+4 ; pobjA-test2() ; call vftable1 而vftable1里存放的是test2()的入口地址; Line 19 xor eax, eax; Line 20 pop ebp ret 0_main ENDP好了,相信到这里你已经对动态联编有了深刻印象。 VC中对象的空间组织和溢出试验 通过上面的分析我们可以对对象空间组织概括如下:| 低地址 |+-+ - objA的起始地址 &objA|pvftable |-+-+ |各成员变量| |+-+ - objA的结束地址 +- +-+ 地址表 vftable| 高地址 | |虚函数1的地址 | +-+ |虚函数2的地址 |

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 办公文档 > 教学/培训

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号