class base {
public:
base():a(10),b(11){}
virtual void fa(){ std::cout << "base a function...\n";}
virtual void fb(){ std::cout << "base b function...\n";}
public:
int a;
int b;
std::string c{"angel"};
};
class derived: public base {
public:
void fa() override { std::cout << "derived a function ...\n";}
void fb() override { std::cout << "derived b function...\n"; }
void fc() { std::cout << "derived c function...\n";}
public:
int c;
};
int main(int argc, char** argv)
{
std::cout << "class base size : " << sizeof(base) << std::endl;
std::cout << "class derived size: " << sizeof(derived) << std::endl;
derived* pd = new derived();
base* pb = new derived();
using func= void(*)();
long int vptr1 = reinterpret_cast<long int>(pb);
long int vptr2 = reinterpret_cast<long int>(pd);
long int* p = (long int*)vptr1;
long int* p1 = (long int*)vptr2;
std::cout << "p " << p << std::endl;
std::cout << "p1 " << p1 << std::endl;
long int* vtaddr = (long int*)(*p);
long int* vtaddr2 = (long int*)(*p1);
std::cout << "vtaddr " << vtaddr << std::endl;
std::cout << "vtaddr2 " << vtaddr2 << std::endl;
func* ptr = (func*)(vtaddr);
(*ptr)();
func* ptrb = (func*)(vtaddr+1);
(*ptrb)();
func* bptr = (func*)(vtaddr2);
(*bptr)();
func* bptrb = (func*)(vtaddr2+1);
(*bptrb)();
std::cout << *(int*)(long int*)(vptr1+8) << std::endl;
std::cout << *(int*)(long int*)(vptr1+12) << std::endl;
std::cout << std::string((char*)(long int*)(vptr1+16))<< std::endl;
pd->fa();
pb->fa();
return 0;
}
以上代码强制调用vtable指向的函数,从安全性角度讲:可以替换虚表的任何函数。
结果是:
class base size : 40 class derived size: 48 p 0x102a84240 p1 0x102a84210 vtaddr 0x10000b090 vtaddr2 0x10000b090 derived a function ...value is ...34 derived b function... derived a function ...value is ...-1746446496 derived b function... 10 11 angel derived a function ...value is ...10 derived a function ...value is ...10
强行使用裸指针调用,得到的成员值明显不对。推测是没有代入隐含的this指针。
下次谈谈如何基于本案列做C++的逆向工程。