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