ILT:Incremental Link Table 增量链接表,(函数地址跳转表) @ILT+100 相当于跳转到弟21个函数 JMP 0xXXXXXXXX (5字节在32位机器)跳转到某个具体函数地址, 所有的call会先到表里,再JMP到具体函数地址
1、普通成员函数
int add_1(int a, int b){return a+b;};
00361810 push ebp
00361811 mov ebp,esp #保存ebp
00361813 sub esp,0CCh #申请栈空间
00361819 push ebx #保存非易失寄存器
0036181A push esi
0036181B push edi
0036181C push ecx #保存类指针
0036181D lea edi,[ebp-0CCh] #初始化申请到的栈空间
00361823 mov ecx,33h
00361828 mov eax,0CCCCCCCCh
0036182D rep stos dword ptr es:[edi]
0036182F pop ecx #把类指针拿出来
00361830 mov dword ptr [ebp-8],ecx #把类指针放在ebp-8的位置
00361833 mov eax,dword ptr [a] #拿第一参数ebp+8
00361836 add eax,dword ptr [b] #拿第二参数ebp+12,结果放在eax 返回类地址
00361839 pop edi #恢复寄存器
0036183A pop esi
0036183B pop ebx
0036183C mov esp,ebp #恢复esp,ebp
0036183E pop ebp
0036183F ret 8 #返回,stdcall
2、构造函数
class son
: public father
{
public:
son(){m_val = 12;}
...
...
003615B3 mov ecx,dword ptr [this] #this指针就是ebp-8
003615B6 call father::father (361073h) #先调用父类的构造
003615BB mov eax,dword ptr [this]
#把虚函数表地址放在类的首地址中
003615BE mov dword ptr [eax],offset son::`vftable' (366740h)
003615C4 mov eax,dword ptr [this]
003615C7 mov dword ptr [eax+4],0Ch #eax+4就是成员变量m_val的位置
003615CE mov eax,dword ptr [this] #构造函数的返回值是this指针
003615D1 pop edi
003615D2 pop esi
003615D3 pop ebx
003615D4 add esp,0CCh #释放栈空间
003615DA cmp ebp,esp #比较栈是否平衡
#调用__RTC_CheckEsp函数 第74个函数,仅仅是为了检查
003615DC call @ILT+365(__RTC_CheckEsp) (361172h)
003615E1 mov esp,ebp #函数返回
003615E3 pop ebp
003615E4 ret
3、析构函数
~son(){m_val = 0;}
......
...... #省略初始化工作
00A01783 mov eax,dword ptr [this]
00A01786 mov dword ptr [eax],offset son::`vftable' (0A06740h) #设置虚函数表
00A0178C mov eax,dword ptr [this]
00A0178F mov dword ptr [eax+4],0 #m_val清零
00A01796 mov ecx,dword ptr [this]
00A01799 call father::~father (0A010C8h) #调用基类的析构
00A0179E pop edi #返回,代码跟构造函数一样,析构函数没有返回值
......
4、类的静态函数
static int add_1(int a, int b){return a+b;};
00F51810 push ebp
00F51811 mov ebp,esp
00F51813 sub esp,0C0h
00F51819 push ebx
00F5181A push esi
00F5181B push edi
00F5181C lea edi,[ebp-0C0h]
00F51822 mov ecx,30h
00F51827 mov eax,0CCCCCCCCh
00F5182C rep stos dword ptr es:[edi] #以上都初始化,发现没有使用类指针,与普通函数无差别
00F5182E mov eax,dword ptr [a]
00F51831 add eax,dword ptr [b]
00F51834 pop edi
00F51835 pop esi
00F51836 pop ebx
00F51837 mov esp,ebp
00F51839 pop ebp
00F5183A ret #返回的时候没有使用ret 8,说明是c标准调用,call后面跟add esp,8
5、静态成员变量
void set_val(int n){m_privete = n;} // m_privete 是静态成员
......
......#仅列出最重要的2句
013C2043 mov eax,dword ptr [n] #获取n的值
013C2046 mov dword ptr [son::m_privete (13C81ACh)],eax #放到一个静态地址里
6、虚函数
father *pfather = newson; #父类指针new一个子类对象,调用父类虚函数
pfather->add_0(2,4); #看调用过程
00FF155E mov esi,esp #先保存esp到esi
00FF1560 push 4 #参数入栈
00FF1562 push 2
#注意这里用mov不是lea,取指针的值,eax放的就是new的类对象的地址
00FF1564 mov eax,dword ptr [ebp-14h]
#类对象地址的首地址的值放的是虚函数表的地址,记下edx的值0x000F6740(看下面虚函数表)
00FF1567 mov edx,dword ptr [eax]
00FF1569 mov ecx,dword ptr [ebp-14h] #ecx一如既往地保存类对象地址
00FF156C mov eax,dword ptr [edx+4] #取到实际函数的地址
00FF156F call eax #调用函数,call一个寄存器,就是运行时多态
00FF1571 cmp esi,esp #检查栈平衡
00FF1573 call @ILT+355(__RTC_CheckEsp) (0FF1168h)
7、虚函数表,以NULL结尾
#虚函数表2个函数,一个地址是0xF110E,另一个0xF120D
0x000F6740 0e 11 0f 00 0d 12 0f 00 00 00 00 00
son::`vector deleting destructor': #父类虚析构,子类的析构函数在虚函数表里
000F110E jmp son::`scalar deleting destructor' (0F1510h)
son::add_0: #父类的add_0是虚函数
000F120D jmp son::add_0 (0F1850h)