11关于虚函数_使用IDA通过虚函数识别构造、析构、虚函数
根据虚函数与构造、析构函数的关系,使用IDA识别C++中的构造、析构、虚函数
#include "stdafx.h"
class CVirtual
{
public:
~CVirtual()
{
printf("~CVirtual");
}
CVirtual()
{
}
CVirtual(int nNumber)
{
m_nNumber = nNumber;
}
virtual int GetNumber()
{
return m_nNumber;
}
virtual void SetNumber(int nNumber)
{
m_nNumber = nNumber;
}
private:
int m_nNumber;
};
int main(int argc, char* argv[])
{
// 获取含有虚函数表的类大小
// int nSize = sizeof(CVirtual);
CVirtual MyVirtual;
CVirtual MyVirtual1(1);
// MyVirtual.SetNumber(argc);
// printf("%d\r\n", MyVirtual.GetNumber());
return 0;
}
直接使用IDA对生成的exe进行分析,先找到main:
.text:00411440 ; __unwind { // _main_0_SEH
.text:00411440 push ebp
.text:00411441 mov ebp, esp
.text:00411443 push 0FFFFFFFFh
.text:00411445 push offset _main_0_SEH
.text:0041144A mov eax, large fs:0
.text:00411450 push eax
.text:00411451 sub esp, 0ECh
.text:00411457 push ebx
.text:00411458 push esi
.text:00411459 push edi
.text:0041145A lea edi, [ebp+var_F8]
.text:00411460 mov ecx, 3Bh
.text:00411465 mov eax, 0CCCCCCCCh
.text:0041146A rep stosd
.text:0041146C mov eax, dword_41801C
.text:00411471 xor eax, ebp
.text:00411473 push eax
.text:00411474 lea eax, [ebp+var_C]
.text:00411477 mov large fs:0, eax
.text:0041147D lea ecx, [ebp+var_18]
.text:00411480 call sub_4111EF //无参构造
.text:00411485 ; try {
.text:00411485 mov [ebp+var_4], 0
.text:0041148C push 1
.text:0041148E lea ecx, [ebp+var_28]
.text:00411491 call sub_411087 //带1个参数构造
.text:00411496 mov [ebp+var_F4], 0
.text:004114A0 lea ecx, [ebp+var_28]
.text:004114A3 call sub_4111AE //析构
.text:004114A3 ; } // starts at 411485
.text:004114A8 mov [ebp+var_4], 0FFFFFFFFh
.text:004114AF lea ecx, [ebp+var_18]
.text:004114B2 call sub_4111AE //析构
.text:004114B7 mov eax, [ebp+var_F4]
.text:004114BD push edx
.text:004114BE mov ecx, ebp
.text:004114C0 push eax
.text:004114C1 lea edx, dword_4114F0
.text:004114C7 call j_@_RTC_CheckStackVars@8 ; _RTC_CheckStackVars(x,x)
.text:004114CC pop eax
call sub_4111AE调用2次很有可能是生成2个对象,析构的时候调用同1个析构函数,
call sub_4111EF和call sub_411087
传入的参数是ecx,但是传入的this指针不一样,很有可能生成了2个对象,所以传入的指针不一样。
并且由于构造函数可以重载,有参和无参构造。
先进入构造函数里面查看:
.text:004115D0 var_CC = byte ptr -0CCh .text:004115D0 var_8 = dword ptr -8 .text:004115D0 .text:004115D0 push ebp .text:004115D1 mov ebp, esp .text:004115D3 sub esp, 0CCh .text:004115D9 push ebx .text:004115DA push esi .text:004115DB push edi .text:004115DC push ecx .text:004115DD lea edi, [ebp+var_CC] .text:004115E3 mov ecx, 33h .text:004115E8 mov eax, 0CCCCCCCCh .text:004115ED rep stosd .text:004115EF pop ecx .text:004115F0 mov [ebp+var_8], ecx .text:004115F3 mov eax, [ebp+var_8] .text:004115F6 mov dword ptr [eax], offset ??_7CVirtual@@6B@ ; const CVirtual::`vftable' .text:004115FC mov eax, [ebp+var_8] .text:004115FF pop edi .text:00411600 pop esi .text:00411601 pop ebx .text:00411602 mov esp, ebp .text:00411604 pop ebp .text:00411605 retn .text:00411605 sub_4115D0 endp
在IDA中 ??_7CVirtual@@6B@ 右键“xref to”和"“xref from"
“xref to”指的是读取这个数据的位置

通过这种方法,可以找到所有的构造和析构函数,因为在构造和析构函数里面会对虚表进行重写(初始化和还原)
“xref from”指的是该地址来自哪里

通过这种方法,可以找到所有的虚函数。

浙公网安备 33010602011771号