-
-
[原创]通过分析RTTI识别类及类之间的继承关系
-
2013-2-21 14:23 6320
-
【文章标题】: 通过分析RTTI识别类及类之间的继承关系
【文章作者】: 绝对小白
【编写语言】: VC
【使用工具】:IDA6.1
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
背景交代
这篇文章是以前学习RTTI的时候写的,很多东西都是参考一此前辈的文章来的,望各位前辈多多包含,别拍砖啊。今天刚刚用到RTTI整理了一下,也不怕各位大牛笑话,因为最近看了厚黑心里学,所有就发上来了~!
【详细过程】
通过分析RTTI识别类及类之间的继承关系
一、什么是RTTI?
RTTI 是“Runtime Type Information”的缩写,意思是:运行时类型信息。RTTI(Run-Time Type Identification)运行时类型识别是由编译器生成的特殊信息,用于支持像dynamic_cast<>和typeid()这样的C++运算符,以及C++异常。
开启RTTI。
在默认情况下VC++6.0是把RTT关闭的。在VC++6.0菜单上的project-->setings-->C/C++进行设置,在Category:选择“C++ Language”,选中“Enable Run-Time Type Information(RTTI)复选框”如图:
三、预备知识补充。
为了实现 RTTI,MSVC编译器在编译完了的二进制可执行文件中加入一些结构体,这些结构体包含了代码中关于类(特别是多态类)的信息。这些结构体是:
1、RTTI Complete Object Locator结构体。
这个结构体在32位系统中占20个字节,其中包含了2个指针,一个指向当前类的信息,另一个指向类的继承关系信息。该结构体信息如下(来源于网上):
struct RTTICompleteObjectLocator
{
DWORD signature; //总是0 ?
DWORD offset; //这个vftable在整个类中的偏移
DWORD cdOffset; //构造函数位移的偏移
struct TypeDescriptor* pTypeDescriptor; //整个类的类型描述符
struct RTTIClassHierarchyDescriptor* pClassDescriptor; //描述继承关系(hierarchy)
};
2、其中TypeDescriptor结构信息如下,这个结构中定义当前类的类名,逆向的时候根据类名可以大概猜出这个类是做什么的。
struct TypeDescriptor{ VOID *pVFTable; //Always points to type_info’s vftable
DWORD spar3; //保留
char *name; //Class Name
}
ClassHierarchyDescriptor结构体。
该结构体记录了类的继承信息,包括基类的数量,以及一个RTTIBaseClassDescriptor结构数组。
struct ClassHierarchyDescriptor{DWORD signature; //总是 zero?DWORD attributes; //bit 0 set = multiple inheritance, bit 1 set = virtual inheritanceDWORD numBaseClasses; //number of classes in pBaseClassArraystruct RTTIBaseClassArray* pBaseClassArray;};
RTTIBaseClassDescriptor
这个结构体记录了关于基类的有关信息,它包括一个指向基类的TypeDescriptor 的指针和一个指向基类的RTTIClassHierarchyDescriptor 的指针另外它还包含有 一 个 PMD 结 构 体。这个结构体记录了这个类中各个基类的位置。
struct RTTIBaseClassDescriptor{struct TypeDescriptor* pTypeDescriptor; //type descriptor of the classDWORD numContainedBases; //number of nested classes following in the Base Class Arraystruct PMD where; //pointer-to-member displacement infoDWORD attributes; //flags, usually 0};
PMD结构体
PMD结构体描述一个基类是如何安置在一个完整的类里。如果是一个简单的继承,它被安置在从对象起始位置开始的一个固定的偏移,这个偏移就是_mdisp_字段。如果它是一个虚基类,那么需要从vbtable得到一个附加的偏移。
struct PMD
{
int mdisp; //成员偏移
int pdisp; //vbtable偏移
int vdisp; //vbtable内偏移
};
四、实战。
启用RTTI。
在开户RTTI后,MSVC编译器在vftable前(偏移-4)设置了一个指针,指向了“Complete Object Locator”(完整对象定位器)的结构。
把下面的代码编译为DEBUG版(什么DEBUG版的,为了更好的学校嘛):
#include <iostream>
class CFather
{
public:
virtual void SetTall(int a)
{
m_ntall=a;
}
virtual void ShowTall()
{
printf("m_ntall=%d\n",m_ntall);
}
public:
CFather(){}
virtual ~CFather(){}
private:
int m_ntall;
};
class CMother
{
public:
virtual void SetWeight(int a)
{
m_nWeight=a;
}
virtual void ShowWeight()
{
printf("m_Weight=%d\n",m_nWeight);
}
public:
CMother(){}
virtual ~CMother(){}
private:
int m_nWeight;
};
class CSon :public CFather,public CMother
{
public:
void SetAge(int a)
{
m_nAge=a;
}
void ShowAge()
{
printf("m_nAge=%d\n",m_nAge);
}
public:
CSon(){}
virtual ~CSon(){}
private:
int m_nAge;
};
int main(int argc, char* argv[])
{
CSon son;
son.SetAge(18);
son.ShowAge();
return 0;
}
IDA分析。
1、定位到虚表
首先来到找到构造函数,如图:
双击“j_??0CSon@@QAE@XZ”来到构造函数实的地方,如图:下面红色代码显示的地方可以看到两张虚表。关于继承的内存部局不了解的请自己查看相关资料。
上图显示的是son对象的内存部局
2、通过虚表,定位RTTICompleteObjectLocator结构,找到类名。
双击“_7CSon@@6BCFather@@@”这一全局变量,来到虚表的位置,如图:
上面已经说过了,RTTICompleteObjectLocator指针就在虚表前偏移-4的地方。也就是上面那个DWORD类型的“??_R4CSon@@6BCFather@@@”。如何确定是一个RTTICompleteObjectLocator结构指什,IDA后面已经给出注释,进一步确认,通过分析RTTICompleteObjectLocator->pTypeDescriptor是不是指向一个有效的TypeDescriptor;检查TypeDescriptor是否正确,可以看TypeDescriptor.name是不是以“.?AV(是VC编译的时候给类别加的的前缀)”开头的字串。
双击“ ??_R4CSon@@6BCFather@@@”,来到RTTICompleteObjectLocator的结构,如图:
通过TypeDescriptor.name检查是否有效,双击“??_R0?AVCSon@@@8”来到TypeDescriptor,如图:
整理后如下图:
找出类的继承信息、继承数量及基类信息。
来到RTTICompleteObjectLocator的结构,如图:
双击“ ??_R3CSon@@8”来到RTTIClassHierarchyDescriptor指针地址,如图:
转为ClassHierarchyDescriptor内存结构整理为,如图:
双击“??_R2CSon@@8”来到BaseClassArray内存地址,如图:
通过以上信息,一层层向上分析,直到找出类的类与类之间的关系。
教程结束。
图片太多,不能一一上传,发了个附件。
【文章作者】: 绝对小白
【编写语言】: VC
【使用工具】:IDA6.1
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
背景交代
这篇文章是以前学习RTTI的时候写的,很多东西都是参考一此前辈的文章来的,望各位前辈多多包含,别拍砖啊。今天刚刚用到RTTI整理了一下,也不怕各位大牛笑话,因为最近看了厚黑心里学,所有就发上来了~!
【详细过程】
通过分析RTTI识别类及类之间的继承关系
一、什么是RTTI?
RTTI 是“Runtime Type Information”的缩写,意思是:运行时类型信息。RTTI(Run-Time Type Identification)运行时类型识别是由编译器生成的特殊信息,用于支持像dynamic_cast<>和typeid()这样的C++运算符,以及C++异常。
开启RTTI。
在默认情况下VC++6.0是把RTT关闭的。在VC++6.0菜单上的project-->setings-->C/C++进行设置,在Category:选择“C++ Language”,选中“Enable Run-Time Type Information(RTTI)复选框”如图:
三、预备知识补充。
为了实现 RTTI,MSVC编译器在编译完了的二进制可执行文件中加入一些结构体,这些结构体包含了代码中关于类(特别是多态类)的信息。这些结构体是:
1、RTTI Complete Object Locator结构体。
这个结构体在32位系统中占20个字节,其中包含了2个指针,一个指向当前类的信息,另一个指向类的继承关系信息。该结构体信息如下(来源于网上):
struct RTTICompleteObjectLocator
{
DWORD signature; //总是0 ?
DWORD offset; //这个vftable在整个类中的偏移
DWORD cdOffset; //构造函数位移的偏移
struct TypeDescriptor* pTypeDescriptor; //整个类的类型描述符
struct RTTIClassHierarchyDescriptor* pClassDescriptor; //描述继承关系(hierarchy)
};
2、其中TypeDescriptor结构信息如下,这个结构中定义当前类的类名,逆向的时候根据类名可以大概猜出这个类是做什么的。
struct TypeDescriptor{ VOID *pVFTable; //Always points to type_info’s vftable
DWORD spar3; //保留
char *name; //Class Name
}
ClassHierarchyDescriptor结构体。
该结构体记录了类的继承信息,包括基类的数量,以及一个RTTIBaseClassDescriptor结构数组。
struct ClassHierarchyDescriptor{DWORD signature; //总是 zero?DWORD attributes; //bit 0 set = multiple inheritance, bit 1 set = virtual inheritanceDWORD numBaseClasses; //number of classes in pBaseClassArraystruct RTTIBaseClassArray* pBaseClassArray;};
RTTIBaseClassDescriptor
这个结构体记录了关于基类的有关信息,它包括一个指向基类的TypeDescriptor 的指针和一个指向基类的RTTIClassHierarchyDescriptor 的指针另外它还包含有 一 个 PMD 结 构 体。这个结构体记录了这个类中各个基类的位置。
struct RTTIBaseClassDescriptor{struct TypeDescriptor* pTypeDescriptor; //type descriptor of the classDWORD numContainedBases; //number of nested classes following in the Base Class Arraystruct PMD where; //pointer-to-member displacement infoDWORD attributes; //flags, usually 0};
PMD结构体
PMD结构体描述一个基类是如何安置在一个完整的类里。如果是一个简单的继承,它被安置在从对象起始位置开始的一个固定的偏移,这个偏移就是_mdisp_字段。如果它是一个虚基类,那么需要从vbtable得到一个附加的偏移。
struct PMD
{
int mdisp; //成员偏移
int pdisp; //vbtable偏移
int vdisp; //vbtable内偏移
};
四、实战。
启用RTTI。
在开户RTTI后,MSVC编译器在vftable前(偏移-4)设置了一个指针,指向了“Complete Object Locator”(完整对象定位器)的结构。
把下面的代码编译为DEBUG版(什么DEBUG版的,为了更好的学校嘛):
#include <iostream>
class CFather
{
public:
virtual void SetTall(int a)
{
m_ntall=a;
}
virtual void ShowTall()
{
printf("m_ntall=%d\n",m_ntall);
}
public:
CFather(){}
virtual ~CFather(){}
private:
int m_ntall;
};
class CMother
{
public:
virtual void SetWeight(int a)
{
m_nWeight=a;
}
virtual void ShowWeight()
{
printf("m_Weight=%d\n",m_nWeight);
}
public:
CMother(){}
virtual ~CMother(){}
private:
int m_nWeight;
};
class CSon :public CFather,public CMother
{
public:
void SetAge(int a)
{
m_nAge=a;
}
void ShowAge()
{
printf("m_nAge=%d\n",m_nAge);
}
public:
CSon(){}
virtual ~CSon(){}
private:
int m_nAge;
};
int main(int argc, char* argv[])
{
CSon son;
son.SetAge(18);
son.ShowAge();
return 0;
}
IDA分析。
1、定位到虚表
首先来到找到构造函数,如图:
双击“j_??0CSon@@QAE@XZ”来到构造函数实的地方,如图:下面红色代码显示的地方可以看到两张虚表。关于继承的内存部局不了解的请自己查看相关资料。
上图显示的是son对象的内存部局
2、通过虚表,定位RTTICompleteObjectLocator结构,找到类名。
双击“_7CSon@@6BCFather@@@”这一全局变量,来到虚表的位置,如图:
上面已经说过了,RTTICompleteObjectLocator指针就在虚表前偏移-4的地方。也就是上面那个DWORD类型的“??_R4CSon@@6BCFather@@@”。如何确定是一个RTTICompleteObjectLocator结构指什,IDA后面已经给出注释,进一步确认,通过分析RTTICompleteObjectLocator->pTypeDescriptor是不是指向一个有效的TypeDescriptor;检查TypeDescriptor是否正确,可以看TypeDescriptor.name是不是以“.?AV(是VC编译的时候给类别加的的前缀)”开头的字串。
双击“ ??_R4CSon@@6BCFather@@@”,来到RTTICompleteObjectLocator的结构,如图:
通过TypeDescriptor.name检查是否有效,双击“??_R0?AVCSon@@@8”来到TypeDescriptor,如图:
整理后如下图:
找出类的继承信息、继承数量及基类信息。
来到RTTICompleteObjectLocator的结构,如图:
双击“ ??_R3CSon@@8”来到RTTIClassHierarchyDescriptor指针地址,如图:
转为ClassHierarchyDescriptor内存结构整理为,如图:
双击“??_R2CSon@@8”来到BaseClassArray内存地址,如图:
通过以上信息,一层层向上分析,直到找出类的类与类之间的关系。
教程结束。
图片太多,不能一一上传,发了个附件。
[培训]内核驱动高级班,冲击BAT一流互联网大厂工 作,每周日13:00-18:00直播授课
赞赏
他的文章
谁下载
pnp2004
ldljlzw
dzhiguo
yhtchf
lylu
xavkm
swqswq
asd
volume
santaclaus
winting
瓶里鱼
xiaofo
pull
bbbsl
dtkalaok
wonsina
cmdxhz
OldBody
dyf
twoseconds
ZENGKEFU
eaglewood
niling
emgg
无极空间
xiaofuy
stevenlong
justinxp
老白干
bestXP
四维杰
hackerjian
wangzesen
fanzzbbs
astrol
yaofengsir
逆转录酶
夜郎传说
chzpro
wangxiyu
无脸男
coffeesoft
hhggccll
MaYil
hackage
kamaeldead
xSpy
victery
cugbin
puppyki
轩辕之风
ffzzy
silence刘
洪伟
神龙小猪
huoyuanjia
terrans
wangaohui
yirucandy
klauslove
aazhiming
年少天下
落伍老兵
xjtdwy
一直被超越
IThacker
ackerush
cmue
雪中的华尔兹
lvxingzhe
sayakacc
int八零
乡下来的妖怪
tankcake
zhaoqike
woshuo没毛病
sculida
Endali
dofes
看原图