12.IDA-虚函数和虚表(vf代表虚函数,vf3代表this指向第三个函数)
vtable
編譯器會為每一個包含虛函數的類(或通過繼承得到的子類)生成一個表,其中包含指向類中每一個虛函數的指針,這樣的表就叫做虛表(vtable)
__vfptr
每個包含虛函數的類對象都獲得__vfptr指針,并且是對象的第一個數據成員
編譯器必須要保證虛函數表的指針存在于對象實例中最前面的位置
在計算對象的總大小時,也必須考慮到虛表指針。比如new,傳遞給new的大小值不僅包括類(以及任何超類)中的所有顯式聲明的字段占用的空間,而且包括虛表指針所需的任何空間?
示例代碼:
IDA分析如下:?
值得注意的是,虛表索引操作非常類似于結構體引用操作。實際上,它們之間并無區別?。因此,我們可以定義一個結構體來表示一個類的虛表的布局,然后利用這個已定義的結構體來提高反匯編代碼清單的可讀性?
這個結構體允許將虛表引用操作重新格式化成以下形式:?
注意:
C++虛函數絕不會被直接引用,也絕不應成為調用交叉引用的目標。所有C++虛函數應由至少一個虛表條目引用,并且始終是至少一個偏移量交叉引用的目標。
我們隨便找到 vf1函數定義,然后點擊它的交叉引用:?
從而跳轉到虛表,其顯示如下:
.rdata:004031B8 const Base::`vftable' dd offset __purecall ; DATA XREF: Base::Base(void)+A↑o
.rdata:004031BC ? ? ? ? ? ? ? ? dd offset Base::vf2(void)
.rdata:004031C0 ? ? ? ? ? ? ? ? dd offset Base::vf3(void)
.rdata:004031C4 ? ? ? ? ? ? ? ? dd offset Base::vf4(void)
.rdata:004031C8 ? ? ? ? ? ? ? ? dd offset const Sub::`RTTI Complete Object Locator'
.rdata:004031CC const Sub::`vftable' dd offset Sub::vf1(void)
.rdata:004031CC ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ; DATA XREF: Sub::Sub(void)+12↑o
.rdata:004031D0 ? ? ? ? ? ? ? ? dd offset Base::vf2(void)
.rdata:004031D4 ? ? ? ? ? ? ? ? dd offset Sub::vf3(void)
.rdata:004031D8 ? ? ? ? ? ? ? ? dd offset Base::vf4(void)
.rdata:004031DC ? ? ? ? ? ? ? ? dd offset Sub::vf5(void)
可以看到,類構造函數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-虚函数和虚表(vf代表虚函数,vf3代表this指向第三个函数)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Z-Stack Home Develop
- 下一篇: caffe使用训练好的模型对自己的一张图