反匯編角度分析VC面向對象機制資料講解_第1頁
反匯編角度分析VC面向對象機制資料講解_第2頁
反匯編角度分析VC面向對象機制資料講解_第3頁
已閱讀5頁,還剩8頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、/target:從內存角度熟悉VC+面向對象機制作為MFC編程的基礎/author:by Reduta/descritption:IA32 + win sp3 + vc6.0 /OD 1.10一:構造函數(shù)的之爭1.1:構造函數(shù)是有返回值的返回當前對象的this 指針基本打開每一本C+的教程,都會對構造函數(shù)有如此類似的描述“構造函數(shù)無返回值,可進行函數(shù)重載” ,但是事實上又如何呢?答案是構造函數(shù)具備返回值,返回值為當前對象的 this 指針。編寫如下代碼 :/示例#include <iostream>using namespace std;class testint a;public

2、:test();void show();test:test()a=1;void test:show()cout<<a<<endl;int main()test hacker;/調用構造函數(shù)eax為構造函數(shù)返回值_asm/借助返回值修改對象數(shù)據(jù)成員mov dword ptr ss:eax,2 /查看修改是否成功 hacker.show();return 0;執(zhí)行上面的程序,對象hacker的數(shù)據(jù)成員a的值將變?yōu)?,將程序載后0D,看關鍵代碼:1刎二戸,'XII 科 1TTTffrpesSinsFr rndumib 目盹115犧raBDEH! CCCGCCCI;FC

3、i flFFGFFFPIT1QIJ fdM:aGl;GGCI;C> stos dword ptr #s: leiptr伽口叩d詡4m羽Fcbp-*EHKii aoifiFFieEDK 6B380E58 IEBN 7FFD3!10Wmou dMJord ptr <s:|lsp aiiSFFStanhb FETjc.dtau尸d ntr 玉玉hiT1執(zhí)行到401590時,注意觀察eax與ecx的值,如圖1所示,004015888D4D FC0040158BE8 AFFCFFFF0040159036:C700 02000000lea ecx,dword ptr ss:ebp-4 call

4、 api.0040123F mov dword ptr ss:eax,200401597 8D4D FClea ecx,dword ptr ss:ebp-40040159A E8 0FFCFFFFcall api.004011AE;hacker 的 this 指針;構造函數(shù);修改對象的數(shù)據(jù)成員;hacker 的 this 指針;hacker 的 show 函數(shù)eax和ecx的值是一樣的,說明構造函數(shù)的確是有返回值,且返回值為當前對象的this指針,重新載入OD,在構造函數(shù)處,F(xiàn)7跟進,如圖2 所示puh ahpOOUR1SD18BECmou ebp T&sp1010150383EC U

5、ksub esp,OO4015D459push ebx00401507弭push esi0Q40150857puh edi000150951push ecx9O401SDA8D7D SClea edl,dword ptr ss:ebp-UU0dUUl5DDB9 11800000iwu ecic ,11flfl015E2B8 CCCCCCCCnou eax fCCCCCCCC0OU015E7F3 : ABrep stos dword ptr ps:ediOOU01SE959popoonoiEA盼D FCiwu duiord ptr ss: &bp-U ,ecx0Q4fl1ED8BHr F

6、CInon eaxtduord ptr ss:et>p-40OU015Fn0700 01oooaoanou duord ptr ds:&axr1(JBhb佔F6&R嶼 FCmoo eax,dord ptr ss:&bp-U1 AlitH *iF0匚匚卩叩川O04O15FA5Epop esiafldSFBSBpop ebxB04ei5FC8BE5mov esp9ebpO04O15FE5Dpop ebp004015FFG3retn,用紅框標識的為關鍵代碼,即構造函數(shù),最后都會執(zhí)行一句指令,將當前對象的this指針保存到eax中,而eax是函數(shù)的返回值。不管是debug

7、版的程序還是release版程序都會執(zhí)行 類似的指令,即無論何時,構造函數(shù)將返回當前對象的this指針。1.2:構造函數(shù)并不一定是函數(shù)一一inline內聯(lián)的影響看到構造函數(shù)并不一定是函數(shù),你可能覺得可笑,這主要受inline內聯(lián)的影響。如果將上面的構造函數(shù)定義在類作用域內即如下代碼,此時測試release版本程序會發(fā)現(xiàn),執(zhí)行結果依然為1,如圖3所示,Press Any ket; toc ontInueclas testint d i public:test(Ka=1;uqid);void test:show() <cout«-a«epdl;>lnt main(0

8、<test hacker;/調用_asn"借助返回值修即修改未遂,release版與debug版程序的最大區(qū)別在于代碼優(yōu)化,使用release版,基本所有的inline函數(shù)都能得到擴展,即此時構造函數(shù)并不是一個函數(shù),而只是指令擴展。將release版程序載入OD,跟進主函數(shù),發(fā)現(xiàn)如下代碼:0040102055push ebp004010218BECmov ebp,esp0040102351push ecx00401024C745 FC 01000000mov dword ptr ss:ebp-4,1 ;構造函數(shù)代碼處0040102B36:C700 02000000mov dwo

9、rd ptr ss:eax,2004010328D4D FClea ecx,dword ptr ss:ebp-400401035E8 C6FFFFFFcall api.004010000040103A33C0xor eax,eax0040103C8BE5mov esp,ebp0040103E5Dpop ebp0040103FC3retn并沒有將test ()構造函數(shù)進仃顯示調用,此時的test()構造函數(shù)只有一句代碼即mov dwordptr ss:ebp-4,1。1.3: C+初始化的過程幾乎每本C+的教程都會告訴我們對象是有構造函數(shù)初始化數(shù)據(jù)成員,但是并不能系統(tǒng)的告訴我們初始化的具體過程,

10、本部分著重分析 C+面向對象數(shù)據(jù)成員初始化的一般過程及各種初始化方式的特點。首先來討論一下C+初始化的一般方法全局對象初始化、初始化列表、構造函數(shù)、static成員的初始化。static數(shù)據(jù)成員是在類內聲明,類外定義的,在定義的時候并不遵守訪問限 定符的限定,一旦定義,static數(shù)據(jù)成員即遵守訪問限定的限制,這里不過分討論static成員,我們來看一下剩余的幾種初始化方式,它們實際上組成了如圖4的初始化層次結構。礎+討軟扔弟化執(zhí)軒為程全局對象的初貽化 科點有猱筠完咸)III初抬花列表(特點是無序詛行)IIII鞫造詁數(shù)(諛序靜造畫霖定叉的代哥用1II全局初始化過程class testint a

11、;public:test()a=1;cout<<"c on structor!"<<e ndl;;test cao;int mai n()cout<<"i n main !"<<e ndl;test dan;return 0;執(zhí)行程序如圖5所示,即在執(zhí)行main函數(shù)之前,需要先調用構造函數(shù)初始化全局對象 動完成的,調用的函數(shù)為 _cinit(),這是在CRT中的一個函數(shù), /初始化列表無序進行ca o,這個過程是有系統(tǒng)自mscvrt.dll 提供。class testint a;const int b;in

12、t c;char d;public:test():a(1),c(2),d(0x61),b(10);int main()test hacker; return 0;初始化列表是 C+ 提供的一種用于初始化 const 數(shù)據(jù)常量的,同時他也能初始化非 const 數(shù)據(jù)常量,上面的代碼反匯編后,主要的代碼如下 :0040108A894D FCmov dword ptr ss:ebp-4,eCx0040108D8B45 FCmov eax,dword ptr ss:ebp-400401090C700 01000000mov dword ptr ds:eax,1;a=1004010968B4D FCmo

13、v eCx,dword ptr ss:ebp-400401099C741 04 0A000000mov dword ptr ds:eCx+4,0A;b=10004010A08B55 FCmov edx,dword ptr ss:ebp-4004010A3C742 08 02000000mov dword ptr ds:edx+8,2;C=2004010AA8B45 FCmov eax,dword ptr ss:ebp-4004010ADC640 0C 61mov byte ptr ds:eax+C,61;d='a'004010B18B45 FCmov eax,dword ptr

14、 ss:ebp-4我們可以清楚的看到, 初始化列表的初始化并不是按照代碼的書寫順序先初始化 a 再初始 化C,而是無序的初始化數(shù)據(jù)成員,這種順序是無法通過 C+進行調整的。/構造函數(shù)初始化有序進行Class test int a;Const int b;int C; Char d;publiC:test():b(10)d=0x61;C=a=1;int main()test haCker;return 0;構造函數(shù)用來初始化, 一定會按照預先設定的代碼執(zhí)行, 因此構造函數(shù)的初始化順序是有 序進行的。主要的反匯編代碼如下:0040108A894D FC0040108D8B45 FC00401090

15、C740 04 0A000000004010978B4D FC0040109AC641 0C 610040109E8B55 FCmov dword ptr ss:ebp-4,eCxmov eax,dword ptr ss:ebp-4mov dword ptr ds:eax+4,0A;將 Const 變量初始化mov eCx,dword ptr ss:ebp-4mov byte ptr ds:eCx+C,61;d='a'mov edx,dword ptr ss:ebp-4004010A1C702 01000000 mov dword ptr ds:edx,1;a=1;004010

16、A7 8B45 FCmov eax,dword ptr ss:ebp-4004010AAC740 08 01000000 mov dword ptr ds:eax+8,1;c=1004010B1 8B45 FC mov eax,dword ptr ss:ebp-4對比不難發(fā)現(xiàn), 先執(zhí)行初始化列表, 然后執(zhí)行構造函數(shù), 因此初始化列表是在構造函數(shù)之 前執(zhí)行的。二: this 指針到底在做什么this 指針在諸多的 C+ 書中都會有類似的描述“始終指向當前正在調用的對象”,那么它到底指向什么呢?答案是它有 ecx 保存,始終指向當前對象的第一個數(shù)據(jù)成員。2.1: C+中變量內存分布C+ 中的變量或

17、者稱為對象在內存的分布是不一樣的, 一方面作用域與存儲類 ras(e register auto static extern)決定了變量分布于內存的堆還是棧,另一方面,先給誰分配內存的順序也 是有區(qū)別的。大致的規(guī)則如下A:單一變量,先聲明先的變量,先分配內存如下代碼int main()int a;int b;會先分配a變量需要的內在,然后分配 b變量需要的內存,因此,a的地址是最大的,即 為ebp-4,而b的地是小的 ebp-8。B:多變量的集合,比如數(shù)組、struct結構體、自定義的對象,先聲明的變量后分配內存。如下代碼:int main()int a3;a0的地址最小的,最后分配內存,a3

18、的地址是最大的,先分配內存。理解了上面的順序我們再來看 this 指針到底做了什么?2.2: this 指針到底在作什么this 指針始終指向當前對象的第一個數(shù)據(jù)成員,即告訴對象的行為(函數(shù))要操作的地址 是什么,用ecx寄存器保存其值。/理解 this 指針class testpublic:int a;int b;int c;test()a=b=c;int mai n()un sig ned thisaddr;test hacker;_asm取this指針mov dword ptr ss:ebp-4,ecxcout< <&hacker.a<<"&qu

19、ot;<<&hacker.b<<""<<&hacker.c<<""<<hex<<thisaddr<<e ndl;return 0;執(zhí)行結果如圖6所示,刖H012FF78H01ZFF740012FF7812ff70Presskey to centa的地址與this指針的值是一樣的,即this指針始終指向對象的第一個數(shù)據(jù)成員的內存地址。 當然這在繼承中略有不同,這點不同在于vbtable的引入。三:虛基類繼承時發(fā)生了什么繼承是什么呢?繼承解實際上抽象了具有相同

20、特性的類,這使得類之間有了一定的層次,最上層的是最核心的,即所有的類的交集, 比如C+的輸入輸出類即為此種層次結構。如圖7描述了 C+的繼承關系,如圖所示使用虛基類的情況是一個平行四邊形的繼承關系時,暫時稱為平行四邊形法則。/虛基類示例 class base public:int a;class d1:virtual public base public: int b;class d2:virtual public base public:int c;class d3:public d1,public d2 public:int sum;int main()d3 ob3;ob3.a=10;ob

21、3.b=20;ob3.c=30;ob3.sum=ob3.a+ob3.b+ob3.c; cout<<ob3.sum<<endl;return 0;3.1:vbtable (虛基類表)是如何工作的將上面的程序載入 OD ,跟進主函數(shù),關鍵代碼如下 /反匯編代碼00401598 6A 01 push 1制標志0040159A 8D4D E8 ss:ebp-18第一個元素 a 的內存地址;這個參數(shù)是一個控lea ecx,dword ptr ; this 指針指向 d1 的 vbtable 地址,即等同于0040159DE8FEFAFFFFcallapi.004010A0;構造函

22、數(shù)依次調用基類子類的構造函數(shù)004015A28B45E8moveax,dwordptrss:ebp-18;d1 vbtable004015A58B4804movecx,dwordptrds:eax+4;eax+4=offset004015A8C7440DE80A00000>movdwordptrss:ebp+ecx-18,0A; this+offset此時我們執(zhí)行完構造函數(shù),觀察棧區(qū)如圖8所示,地址數(shù)值注釋p012FF6OCCI CClcccccc ccccecB012FF6S ob9Q012FF6C0O1ZFF7n Ob380012FF7U Ot)3*CIO00OH46E01C0000

23、1EOffset api d9:<vbtable -offset api.dS;'0O12FF79 Ob3+1B0O12FF7C oto3*1ii一00003C ooooon此時構造函數(shù)將虛基類的vbtable壓入棧中,我們dd vbtable的內容,如圖9所示。地址數(shù)值I注釋OU46E030CB46EC3SO0U6E03C0tHl6Efl4U89680806nOBOOBOS00000008BB0Bfl09G綜合分析,得出vbtable的結構如下:vbtable strucx1 dw ?offset dw ?x2 dw ?vbtable ends其中offset指明了當前數(shù)據(jù)成員

24、距離惟一副本的偏移,在此程序中即為d1中vbtable所在棧地址與其數(shù)據(jù)成員a的偏移地址,即this虛基類通過vbtable中偏移+4的偏移量來定位多副本程序,從而實現(xiàn)子類中只有一個 虛基類的副本。3.2:vbtable是如何引入的重新載入程序,在 40159d處跟進構造函數(shù),會發(fā)現(xiàn)如下代碼:;保存基址;開辟新棧幀sub為新棧幀分配相應的內存00401620 >55 push ebp00401621 8BE mov ebp,esp0040162383EC 44esp,440040162653push ebx0040162756push esi0040162857push edi00401

25、62951pushecx;保存ecx,因為ecx要作為初始化的計數(shù)器0040162A8D7D BClea edi,dword ptr ss:ebp-440040162DB9 11000000mov ecx,1100401632B8CCCCCCCCmov eax,CCCCCCCC00401637F3:ABrep stos dword ptr es:edi0040163959popecx;this指針出棧0040163A894DFCmov dwordptrss:ebp-4,ecx;保存ecx0040163D837D08 00cmp dwordptrss:ebp+8,0;參數(shù)1與0比較以判斷是否使用

26、虛基類0040164174 13je short api.00401656004016438B45 FCmov eax,dword ptr ss:ebp-400401646C70028E04600movdwordptr ds:eax,offsetapi.d3:'vbtable'd2 的 vbtable0040164C8B4D FCmov ecx,dword ptr ss:ebp-40040164FC741081CE04600mov dwordptr ds:ecx+8,offsetapi.d3:'vbtable'd1 的 vbtable分析40163d處的代碼,為

27、 cmp dword ptr ss:ebp+8,0,對于任何一個函數(shù)來說,它的棧區(qū) 結構應該如圖10所示,C+函數(shù)橫區(qū)分布簡略圉即站e寄存證血內容匝童列裘回覽址 MrHB開始為畫議琴數(shù)而此時的ebp+8即為參數(shù)1,因此在使用虛基類時,總會先push 1用于控制判斷是否有虛基類,將將虛基類的vbtable保存到其多副本數(shù)據(jù)成員區(qū),在本程序中即為d1和d2數(shù)據(jù)成員的a位置處。綜上所述,當使用虛基類時,構造函數(shù)會通過一個標志控制參數(shù),將vbtable的地址保存到多副本數(shù)據(jù)成員的內存位置,對應于本程序的變量a,當訪問具有多副本變量時,通過vbtable+4處的偏移值+this指針即可,這保證了繼承時子

28、類中只有基類的一個數(shù)據(jù)成員副本。四:多態(tài)到底為何物實際上C+面向對象程序設計的重要的問題是解決類與類之間的關系, 可以簡單的理解為完全不同的類、大部分不同的類、大部分相同的類、 可以簡稱為類的四象,如圖11所示,類與類之間的關系, 完全相同的類。我們C+面自對象的類E9象描迷結合太極四象更容易理解類與類的關系。多態(tài)即為只有一小部分相似的類的關系,反過來說即為大部分不同的類關系,這種關系通過運行時的vftable來完成。示例class testpublic:virtual void vfun c()cout<<"base's vfun c"<<

29、e ndl;;class d1:public testpublic:void vfun c()cout<<"d1's vfun c!"<<e ndl;class d2:public testpublic:void vfun c()cout<<"d2's vfun c!"<<e ndl;int mai n() test a,*p; d1 b; d2 c; p=&a; p->vfunc(); p=&b; p->vfunc(); p=&c; p->vfun

30、c(); return 0; 將上面的函數(shù)反匯編一下。/反匯編上面的程序分析虛函數(shù)機制004012C88D4DFCleaecx,dwordptrss:ebp-4; this 指針 a004012CBE8 6CFDFFFFcall api.0040103C004012D08D4DF4leaecx,dwordptrss:ebp-C; this 指針 b004012D3E8 69FDFFFFcall api.00401041004012D88D4DF0leaecx,dwordptrss:ebp-10; this 指針 c004012DBE8 48FDFFFFcall api.00401028004012E08D45FCleaeax,dwordptrss:ebp-4; 對

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論