C++ Internals: VC RTTI - 基本数据结构

来源:互联网 发布:成都软件开发 编辑:程序博客网 时间:2024/05/21 07:49

相关资源:
Reversing Microsoft Visual C++ Part II: Classes, Methods and RTTI
Reversing C++

C++的RTTI一旦遇上了多重和虚继承,简直就是噩梦 -.-

这里介绍一下VC中用来表示RTTI的内部数据结构(具体可以参考《Reversing C++》里的描述)。利用下面的程序可以察看多态类的RTTI信息,我们可以借此熟悉一下RTTI到底长什么样子 :-)

#include <windows.h>

#include <iostream>
using namespace std;

#include <typeinfo>
using std::type_info;

typedef type_info TypeDescriptor;

struct PMD
{
    ptrdiff_t mdisp; //vftable offset
    ptrdiff_t pdisp; //vbtable offset
    ptrdiff_t vdisp; //vftable offset (for virtual base class)

    void Output();
};

struct _s_RTTICompleteObjectLocator;
struct _s_RTTIClassHierarchyDescriptor;
struct _s_RTTIBaseClassDescriptor;

struct _s_RTTICompleteObjectLocator
{
    DWORD signature;
    DWORD offset; //vftable offset to this
    DWORD cdOffset;
    TypeDescriptor *pTypeDescriptor;
    _s_RTTIClassHierarchyDescriptor *pClassHierarchyDescriptor;

    void Output(size_t tabs);
};
struct _s_RTTIClassHierarchyDescriptor
{
    DWORD signature;
    DWORD attributes; //bit 0 multiple inheritance, bit 1 virtual inheritance
    size_t numBaseClasses; //at least 1 (all base classes, including itself)
    _s_RTTIBaseClassDescriptor **pBaseClassArray;

    void Output(size_t tabs);
};
struct _s_RTTIBaseClassDescriptor
{
    TypeDescriptor *pTypeDescriptor;
    size_t numBaseClasses; //direct base classes
    PMD pmd; //Len=0xC
    DWORD attributes;
    _s_RTTIClassHierarchyDescriptor *pClassHierarchyDescriptor; //of this base class

    void Output(size_t tabs);
};

void PMD::Output()
{
    cout<<'('<<mdisp<<','<<pdisp<<','<<vdisp<<')';
}

void OutputTab(size_t tabs) {for(size_t i=0;i<tabs;++i) cout<<'/t';}
void _s_RTTICompleteObjectLocator::Output(size_t tabs)
{
    OutputTab(tabs);
    cout<<"CompleteObjectLocator:"<<endl;
    OutputTab(tabs);
    cout<<"signature:"<<signature<<endl;
    OutputTab(tabs);
    cout<<"offset:"<<offset<<endl;
    OutputTab(tabs);
    cout<<"cdOffset:"<<cdOffset<<endl;
    OutputTab(tabs);
    cout<<"pTypeDescriptor:"<<pTypeDescriptor->name()<<endl;
    OutputTab(tabs);
    cout<<"pClassHierarchyDescriptor:"<<endl;
    pClassHierarchyDescriptor->Output(tabs+1);
    cout<<endl;
    cout<<endl;
}
void _s_RTTIClassHierarchyDescriptor::Output(size_t tabs)
{
    OutputTab(tabs);
    cout<<"signature:"<<signature<<endl;
    OutputTab(tabs);
    cout<<"attributes:"<<attributes<<endl;
    for (size_t i=0;i<numBaseClasses;++i) {
        OutputTab(tabs);
        cout<<"base class "<<i+1<<":"<<endl;
        pBaseClassArray[i]->Output(tabs+1);
    }
}
void _s_RTTIBaseClassDescriptor::Output(size_t tabs)
{
    OutputTab(tabs);
    cout<<"pTypeDescriptor:"<<pTypeDescriptor->name()<<endl;

    OutputTab(tabs);
    cout<<"numBaseClasses:"<<numBaseClasses<<endl;
    OutputTab(tabs);
    cout<<"pmd:";
    pmd.Output();
    cout<<endl;
    OutputTab(tabs);
    cout<<"attributes:"<<attributes<<endl;
}

template<typename R> //only ptrdiff_t and size_t allowed
R ReadData(size_t ptr)
{
    return *((const R *)ptr);
}
template<typename R,typename T>
R ReadData(const T *ptr)
{
    return ReadData<R>((size_t)ptr);
}

//We assume the vftable is at offset 0
//If it is not the case, we assume the vbtable should be at offset 0, and with its first entry equal to 0 (point to itself).
//Then its second entry should contain the offset of vftable
template<typename T>
_s_RTTICompleteObjectLocator *GetCompleteObjectLocator(const T *ptr) //not have vbtable
{
    ptrdiff_t offset=0;
    if (ReadData<ptrdiff_t>(ReadData<size_t>(ptr))==0) offset=ReadData<ptrdiff_t>(ReadData<size_t>(ptr)+4);
    return (_s_RTTICompleteObjectLocator *)(ReadData<size_t>(ReadData<size_t>((size_t)ptr+offset)-4));
}

#pragma warning(disable:4584)

class A1
{
public:
    virtual ~A1() {}
private:
    int data;
};
class A2
{
public:
    virtual ~A2() {}
private:
    int data;
};
class B1:virtual public A1,virtual public A2
{
public:
    virtual ~B1() {}
    virtual void FunB1() {}
private:
    int data;
};
class B2:public A1,public A2
{
public:
    virtual ~B2() {}
    virtual void FunB2() {}
private:
    int data;
};
class C:public B1,virtual public B2
{
public:
    virtual ~C() {}
    virtual void FunC() {}
private:
    int data;
};
class D:public A1,virtual public A2
{
public:
    virtual ~D() {}
    virtual void FunD() {}
private:
    int data;
};
class E:public C,public D
{
public:
    virtual ~E() {}
    virtual void FunE() {}
private:
    int data;
};

#include <cstddef>

template<size_t N>
class Evil1:public Evil1<N-1>,public Evil1<N-2>
{
public:
    virtual ~Evil1() {}
};
template<size_t N>
class Evil2:virtual public Evil2<N-1>,public Evil2<N-2>
{
public:
    virtual ~Evil2() {}
};

template<size_t N>
class Evil3:public Evil3<N-1>,virtual public Evil3<N-2>
{
public:
    virtual ~Evil3() {}
};
template<size_t N>
class Evil4:virtual public Evil4<N-1>,virtual public Evil4<N-2>
{
public:
    virtual ~Evil4() {}
};

template<> class Evil1<0> {publicvirtual ~Evil1() {}};
template<> class Evil1<1> {publicvirtual ~Evil1() {}};
template<> class Evil2<0> {publicvirtual ~Evil2() {}};
template<> class Evil2<1> {publicvirtual ~Evil2() {}};
template<> class Evil3<0> {publicvirtual ~Evil3() {}};
template<> class Evil3<1> {publicvirtual ~Evil3() {}};
template<> class Evil4<0> {publicvirtual ~Evil4() {}};
template<> class Evil4<1> {publicvirtual ~Evil4() {}};

int main()
{
    _s_RTTICompleteObjectLocator *pCompleteObjectLocator;

    A1 a1;
    A2 a2;
    B1 b1;
    B2 b2;
    C c;
    D d;
    E e;

    pCompleteObjectLocator=GetCompleteObjectLocator(&a1);
    if (pCompleteObjectLocator) pCompleteObjectLocator->Output(0);
    pCompleteObjectLocator=GetCompleteObjectLocator(&b1);
    if (pCompleteObjectLocator) pCompleteObjectLocator->Output(0);
    pCompleteObjectLocator=GetCompleteObjectLocator(&b2);
    if (pCompleteObjectLocator) pCompleteObjectLocator->Output(0);
    pCompleteObjectLocator=GetCompleteObjectLocator(&c);
    if (pCompleteObjectLocator) pCompleteObjectLocator->Output(0);
    pCompleteObjectLocator=GetCompleteObjectLocator(&d);
    if (pCompleteObjectLocator) pCompleteObjectLocator->Output(0);
    pCompleteObjectLocator=GetCompleteObjectLocator(&e);
    if (pCompleteObjectLocator) pCompleteObjectLocator->Output(0);

    Evil1<5> e1;
    Evil2<5> e2;
    Evil3<5> e3;
    Evil4<5> e4;
    pCompleteObjectLocator=GetCompleteObjectLocator(&e1);
    if (pCompleteObjectLocator) pCompleteObjectLocator->Output(0);
    pCompleteObjectLocator=GetCompleteObjectLocator(&e2);
    if (pCompleteObjectLocator) pCompleteObjectLocator->Output(0);
    pCompleteObjectLocator=GetCompleteObjectLocator(&e3);
    if (pCompleteObjectLocator) pCompleteObjectLocator->Output(0);
    pCompleteObjectLocator=GetCompleteObjectLocator(&e4);
    if (pCompleteObjectLocator) pCompleteObjectLocator->Output(0);
}

转自:http://blog.csdn.net/vbvan/article/details/1907741

原创粉丝点击