12.IDA-虚函数和虚表
vtable
編譯器會(huì)為每一個(gè)包含虛函數(shù)的類(或通過繼承得到的子類)生成一個(gè)表,其中包含指向類中每一個(gè)虛函數(shù)的指針,這樣的表就叫做虛表(vtable)
__vfptr
每個(gè)包含虛函數(shù)的類對象都獲得__vfptr指針,并且是對象的第一個(gè)數(shù)據(jù)成員
編譯器必須要保證虛函數(shù)表的指針存在于對象實(shí)例中最前面的位置
在計(jì)算對象的總大小時(shí),也必須考慮到虛表指針。比如new,傳遞給new的大小值不僅包括類(以及任何超類)中的所有顯式聲明的字段占用的空間,而且包括虛表指針?biāo)璧娜魏慰臻g?
示例代碼:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
IDA分析如下:?
值得注意的是,虛表索引操作非常類似于結(jié)構(gòu)體引用操作。實(shí)際上,它們之間并無區(qū)別?
。因此,我們可以定義一個(gè)結(jié)構(gòu)體來表示一個(gè)類的虛表的布局,然后利用這個(gè)已定義的結(jié)構(gòu)體來提高反匯編代碼清單的可讀性?
?
這個(gè)結(jié)構(gòu)體允許將虛表引用操作重新格式化成以下形式:?
?
注意:
C++虛函數(shù)絕不會(huì)被直接引用,也絕不應(yīng)成為調(diào)用交叉引用的目標(biāo)。所有C++虛函數(shù)應(yīng)由至少一個(gè)虛表?xiàng)l目引用,并且始終是至少一個(gè)偏移量交叉引用的目標(biāo)。
我們隨便找到 vf1函數(shù)定義,然后點(diǎn)擊它的交叉引用:?
?
從而跳轉(zhuǎn)到虛表,其顯示如下:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
可以看到,類構(gòu)造函數(shù)Sub:: Sub(void)使用了虛表的地址Sub::Sub(void)+12↑o, 那是因?yàn)閚ew sub 調(diào)用了sub的隱式構(gòu)造函數(shù)?
windbg觀察:?
注意,Base的虛表第一個(gè)是002816e4 Test!purecall,這時(shí)因?yàn)樵贐ase中,沒有針對純虛函數(shù)vf1的實(shí)現(xiàn),所以在Base的虛表中并沒有存儲(chǔ)vf1的地址,這時(shí),編譯器會(huì)插入一個(gè)錯(cuò)誤處理函數(shù)的地址,通常,該函數(shù)名為purecall,一旦它被調(diào)用,程序就會(huì)被終止
附?
可以觀察到:
1.new指針不為空,才會(huì)調(diào)用構(gòu)造函數(shù),這是由Visual C++的內(nèi)部機(jī)制來保證的?
2.函數(shù)的虛表位置一般都可以在構(gòu)造函數(shù)中找到(很明顯,this指針指向的地址就是虛表的位置)
總結(jié)
以上是生活随笔為你收集整理的12.IDA-虚函数和虚表的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 10.IDA-基本操作
- 下一篇: 14.IDA-XREF(交叉引用)概述