码迷,mamicode.com
首页 > 编程语言 > 详细

C++虚函数:虚指针、虚表、虚函数入口地址

时间:2015-04-18 08:53:45      阅读:355      评论:0      收藏:0      [点我收藏+]

标签:

测试程序:

//test.c
#include"stdio.h"
#include"string.h"
class GSVirtual
{
public:
	void gsv(char *src)
	{
		char buf[200];
		strcpy(buf,src);
		vir2();
	}
	virtual void vir1()
	{
		printf("vir1");
	}
	virtual void vir2()
	{
		printf("vir2");
	}
};
int main(int argc,char *argv[])
{
	GSVirtual test;
	test.gsv(argv[1]);
	return 0;
}
在linux下编译:
$g++ -o vtabletest ./vtabletest.c
在ida下查看vtabletest的反汇编,找到关键函数点 gsv(char *src):

技术分享
该函数中调用了虚函数vir2(),虽然gsv显示只有一个参数,但是实际上默认还有另一个参数:虚指针,查看调用gsv时,参数入栈可发现,有两个参数入栈:
技术分享
然后,我们回到gsv函数中,其中首先分配了当前栈帧空间:
.text:08048538 55                                               push    ebp
.text:08048539 89 E5                                         mov     ebp, esp
.text:0804853B 81 EC F8 00 00 00                  sub     esp, 0F8h
然后,将第一个参数复制到当前栈帧中:注意这个参数就是虚指针的地址(一般在上一个函数的栈帧中)
.text:08048541 8B 45 08                                      mov     eax, [ebp+arg_0]      //arg0=8
.text:08048544 89 85 24 FF FF FF                      mov     [ebp+var_DC], eax   //var_DC=-0XDC
后面,函数会分配函数的局部变量的栈帧中的位置,然后执行strcpy(buf,src)
然后调用虚函数vir2(),我们主要来分析这一段代码:
.text:08048576 8B 85 24 FF FF FF                             mov     eax, [ebp+var_DC]    //将虚指针地址赋值给eax
.text:0804857C 8B 00                                         mov     eax, [eax]         //提取虚指针内存地址中的虚表入口地址,一般在.rodata中
.text:0804857E 83 C0 04                                      add     eax, 4             //由于调用的是vir2(),因此,该虚函数地址在虚表中的位置偏移4*1 bytes
.text:08048581 8B 10                                         mov     edx, [eax]        //提取vir2()虚函数的入口地址
.text:08048583 8B 85 24 FF FF FF                             mov     eax, [ebp+var_DC]   
.text:08048589 89 04 24                                      mov     [esp], eax                //虚指针继续入栈,可视为为下一个函数调用的参数
.text:0804858C FF D2                                         call    edx            //调用vir2()
在linux中,用gdb调试:
在0x8048576处下断点后,查看相关内存信息:
技术分享
可对照ida下的汇编代码看,ebp+8和ebp-0xdc 存储的都是虚指针地址0xbffff2dc 在上一个函数的栈帧中
虚指针指向地址0x80486c8,即虚表地址
虚表中按顺序存储了每个虚函数的入口地址。
技术分享
0x80485a2 和0x80485b6分别就是虚函数vir1()和vir2()的地址:
技术分享

最后,测试程序存在缓冲区溢出漏洞,在gs保护下,则可通过覆盖虚表指针来劫持控制流。



C++虚函数:虚指针、虚表、虚函数入口地址

标签:

原文地址:http://blog.csdn.net/ben_chang/article/details/45101873

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!