日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

7.IDA-创建结构体

發(fā)布時間:2024/4/11 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 7.IDA-创建结构体 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

結(jié)構(gòu)體分類

結(jié)構(gòu)體的一個顯著特點在于,結(jié)構(gòu)體中的數(shù)據(jù)字段是通過名稱訪問,而不是像數(shù)組那樣通過索引訪問。不好的是,字段名稱被編譯器轉(zhuǎn)換成了數(shù)字偏移量。結(jié)果,在反匯編代碼清單中,訪問結(jié)構(gòu)體字段的方式看起來與使用常量索引訪問數(shù)組元素的方式極其相似。

注意的是,結(jié)構(gòu)體中有個內(nèi)存對齊規(guī)則,所以不要認為編譯器會利用所需的最小空間來分配結(jié)構(gòu)體。默認情況下,編譯器會設(shè)法將結(jié)構(gòu)體字段與內(nèi)存地址對齊,以最有效地讀取和寫入這些字段

1. 全局分配的結(jié)構(gòu)體

和全局分配的數(shù)組一樣,編譯器在編譯時可獲知全局分配的結(jié)構(gòu)體的地址。這使得編譯器能夠在編譯時計算出結(jié)構(gòu)體中每個成員的地址,而不必在運行時進行任何計算。

如下代碼:

[cpp]?view plaincopy
  • struct?stTest??
  • {??
  • ????int????f1;??
  • ????short??f2;??
  • ????char???f3;??
  • ????int????f4;??
  • ????double?f5;??
  • };??
  • stTest?g_st;??
  • void?fun()??
  • {??
  • ????g_st.f1?=?10;??
  • ????g_st.f2?=?20;??
  • ????g_st.f3?=?30;??
  • ????g_st.f4?=?40;??
  • ????g_st.f5?=?50.0;??
  • }??
  • 對應(yīng)匯編為:可以看到,在這個反匯編代碼清單中,訪問結(jié)構(gòu)體成員不需要任何算術(shù)計算,如果沒有源代碼,你根本無法斷定這個程序使用了結(jié)構(gòu)體。

    [cpp]?view plaincopy
  • push????ebp??
  • mov?????ebp,?esp??
  • mov?????dword_403018,?10?;?int?f1?=?10??
  • mov?????eax,?20??
  • mov?????word_40301C,?ax?;?word?f2?=?20??
  • mov?????byte_40301E,?30?;?byte?f3?=?30??
  • mov?????dword_403020,?40?;?int?f4?=?40??
  • fld?????ds:dbl_4020E0???;?f5?=?dbl_403028?=?50.0??
  • fstp????dbl_403028??
  • pop?????ebp??
  • retn??

  • 2. 棧分配的結(jié)構(gòu)體

    同樣,僅僅根據(jù)棧布局,同樣很難識別出棧分配的結(jié)構(gòu)體。

    [cpp]?view plaincopy
  • void?fun()??
  • {??
  • ????stTest?l_st;??
  • ????l_st.f1?=?10;??
  • ????l_st.f2?=?20;??
  • ????l_st.f3?=?30;??
  • ????l_st.f4?=?40;??
  • ????l_st.f5?=?50.0;??
  • }??
  • 對應(yīng)匯編為:同樣,訪問結(jié)構(gòu)體中的字段不需要進行任何算術(shù)計算,因為在編譯時,編譯器能夠確定棧幀內(nèi)每個字段的相對偏移量

    [cpp]?view plaincopy
  • 000?push????ebp??
  • 004?mov?????ebp,?esp??
  • 004?sub?????esp,?18h??
  • 01C?mov?????[ebp+var_18],?10??
  • 01C?mov?????eax,?14h??
  • 01C?mov?????[ebp+var_14],?ax??
  • 01C?mov?????[ebp+var_12],?30??
  • 01C?mov?????[ebp+var_10],?40??
  • 01C?fld?????ds:dbl_4020E0??
  • 01C?fstp????[ebp+var_8]??
  • 01C?mov?????esp,?ebp??
  • 004?pop?????ebp??
  • 000?retn??
  • 3. 堆分配的結(jié)構(gòu)體

    由于結(jié)構(gòu)體的地址在編譯時未知,編譯器別無選擇,只有生成代碼來計算每個字段在結(jié)構(gòu)體中的正確偏移量。

    如果一個結(jié)構(gòu)體在堆中分配,那么對編譯器來說,引用該結(jié)構(gòu)體的唯一線索就是指向該結(jié)構(gòu)體起始地址的指針。

    [cpp]?view plaincopy
  • void?fun()??
  • {??
  • ????stTest*?pst?=?new?stTest;??
  • ????pst->f1?=?10;??
  • ????pst->f2?=?20;??
  • ????pst->f3?=?30;??
  • ????pst->f4?=?40;??
  • ????pst->f5?=?50.0;??
  • }??
  • 對應(yīng)匯編為:

    [cpp]?view plaincopy
  • push????ebp??
  • mov?????ebp,?esp??
  • sub?????esp,?8??
  • push????24??????????????;?unsigned?int??
  • call??????2@YAPAXI@Z????;?operator?new(uint)??
  • add?????esp,?4??
  • mov?????[ebp+var_8],?eax?;?eax為pst指針,var_8也是??
  • mov?????eax,?[ebp+var_8]??
  • mov?????[ebp+var_4],?eax??
  • mov?????ecx,?[ebp+var_4]?;?ecx?=?pst??
  • mov?????dword?ptr?[ecx],?10?;?(int*)pst?=?10??
  • mov?????edx,?20??
  • mov?????eax,?[ebp+var_4]?;?eax?=?pst??
  • mov?????[eax+4],?dx?????;?(word*)(pst+4)?=?20??
  • mov?????ecx,?[ebp+var_4]?;?ecx?=?pst??
  • mov?????byte?ptr?[ecx+6],?30?;?(byte*)(pst+6)=30,驗證了第二個是word字節(jié)??
  • mov?????edx,?[ebp+var_4]?;?edx?=?pst??
  • mov?????dword?ptr?[edx+8],?40?;?(int*)(pst+8)?=?40??
  • mov?????eax,?[ebp+var_4]?;?eax?=?pst??
  • fld?????ds:dbl_4020F0??
  • fstp????qword?ptr?[eax+10h]?;?(dq)(pst+16)=50.0??
  • mov?????esp,?ebp??
  • pop?????ebp??
  • retn??
  • 4. 結(jié)構(gòu)體數(shù)組

    [cpp]?view plaincopy
  • void?fun()??
  • {??
  • ????stTest*?pst?=?new?stTest[2];??
  • ????pst[1].f1?=?10;??
  • ????pst[1].f2?=?20;??
  • ????pst[1].f3?=?30;??
  • ????pst[1].f4?=?40;??
  • ????pst[1].f5?=?50.0;??
  • }??
  • 反匯編沒什么區(qū)別:與上面相比,每項加了24

    [cpp]?view plaincopy
  • push????ebp??
  • mov?????ebp,?esp??
  • sub?????esp,?8??
  • push????48??????????????;?48/2?=?24??
  • call??????2@YAPAXI@Z????;?operator?new(uint)??
  • add?????esp,?4??
  • mov?????[ebp+var_8],?eax??
  • mov?????eax,?[ebp+var_8]??
  • mov?????[ebp+var_4],?eax??
  • mov?????ecx,?[ebp+var_4]??
  • mov?????dword?ptr?[ecx+24],?10?;?pst+24,注意+24??
  • mov?????edx,?20??
  • mov?????eax,?[ebp+var_4]??
  • mov?????[eax+1Ch],?dx??
  • mov?????ecx,?[ebp+var_4]??
  • mov?????byte?ptr?[ecx+30],?30?;?pst+24+6??
  • mov?????edx,?[ebp+var_4]??
  • mov?????dword?ptr?[edx+32],?40?;?pst+24+8??
  • mov?????eax,?[ebp+var_4]??
  • fld?????ds:dbl_4020F0??
  • fstp????qword?ptr?[eax+40]?;?pst+14+16??
  • mov?????esp,?ebp??
  • pop?????ebp??
  • retn??

  • 創(chuàng)建結(jié)構(gòu)體

    IDA之所以在分析階段無法識別結(jié)構(gòu)體,可能源于兩個原因。首先,雖然IDA了解某個結(jié)構(gòu)體的布局,但它并沒有足夠的信息,能夠判斷程序確實使用了結(jié)構(gòu)體。其次,程序中的結(jié)構(gòu)體可能是一種IDA對其一無所知的非標準結(jié)構(gòu)體。在這兩種情況下,問題都可以得到解決,且首先從Structures窗口下手

    1.添加結(jié)構(gòu)體

    Structures窗口的前4行文本用于提醒用戶該窗口中可能進行的操作。

    使用熱鍵INSERT啟動

    指定結(jié)構(gòu)體的名稱并單擊OK按鈕后,IDA將在Structures窗口中創(chuàng)建一個空結(jié)構(gòu)體定義

    2.編輯結(jié)構(gòu)體成員

    (1)要給結(jié)構(gòu)體添加新字段,將光標放在結(jié)構(gòu)體定義的最后一行(包含ends的那一行)并按下D鍵。新字段的大小取決于你在數(shù)據(jù)轉(zhuǎn)盤上選擇的第一個大小

    (2)如果需要修改字段的大小,首先將光標放在新字段的名稱上,然后重復按下D鍵,使數(shù)據(jù)轉(zhuǎn)盤上的數(shù)據(jù)類型開始循環(huán),從而為新字段選擇正確的數(shù)據(jù)大小。另外,你還可以使用Options?Setup Data Types來指定一個在數(shù)據(jù)轉(zhuǎn)盤上不存在的大小。如果新字段是一個數(shù)組,右擊其名稱并在上下文菜單中選擇Array

    (3)要更改一個結(jié)構(gòu)體字段的名稱,單擊字段名稱并按下N鍵,或者右擊該名稱并在上下文菜單中選擇ReName,然后在輸入框中輸入一個名稱即可。

    ?

    以下是幫助說明

    ??一個字段的字節(jié)偏移量在Structures窗口的左側(cè)顯示。

    ?

    ??結(jié)構(gòu)體的新大小會在結(jié)構(gòu)體定義的第一行及時更新出來。

    ?

    ? ?可以給一個結(jié)構(gòu)體字段添加注釋,就像給任何反匯編行添加注釋一樣。?

    ?

    ? ?只有當一個字段是結(jié)構(gòu)體中的最后一個字段時,使用U鍵才能刪除該字段。對于其他字段,按下U鍵只是變成undefined,可以通過D鍵恢復

    ?

    ??IDA并不區(qū)分已壓縮和未壓縮的結(jié)構(gòu)體。為將字段適當對齊,如果你需要填補字節(jié),那么你必須負責添加這些字節(jié)。填補字節(jié)最好作為適當大小的啞字段添加。在添加額外的字段后,你可以選擇取消或保留這些字段的定義。

    ?

    ?分配到結(jié)構(gòu)體中間的字節(jié)只有在取消關(guān)聯(lián)字段的定義后(undefined狀態(tài)),Edit?Shrink Struct Type(縮小結(jié)構(gòu)體類型)即可刪除被取消定義的字節(jié)。

    ?

    ??也可以在結(jié)構(gòu)體的中間添加新的字節(jié):選擇新字節(jié)后面的一個字段,然后使用Edit?Expand Struct Type(擴大結(jié)構(gòu)體類型)在選中的字段前插入一定數(shù)量的字節(jié)。

    ?如果知道結(jié)構(gòu)體的大小,而不了解它的布局,你需要創(chuàng)建兩個字段。第一個字段為一個數(shù)組,它的大小為結(jié)構(gòu)體的大小減去1個字節(jié)(size-1);第二個字段應(yīng)為1個字節(jié)。創(chuàng)建第二個字段后,取消第一個(數(shù)組)字段的定義。這樣,結(jié)構(gòu)體的大小被保留下來,隨后,當你進一步了解該結(jié)構(gòu)體的布局后,你可以回過頭來定義它的字段及其大小。

    創(chuàng)建完成后如下:

    ?

    3.折疊打開結(jié)構(gòu)體

    可以選擇結(jié)構(gòu)體中的任何字段并按下數(shù)字鍵盤中的減號鍵,將結(jié)構(gòu)體的定義折疊成一行摘要,雙擊結(jié)構(gòu)體名稱也可以打開該定義。(或ctrl+/ctrl-)

    ?

    使用結(jié)構(gòu)體模板

    1.右擊中,可在上下文菜單上看到Structure offset選項:很明確的說明了它可以是stTest.f5+24(pst[1].f5 = 50.0;)

    2.另一種方法,可以將棧和全局變量格式化成整個結(jié)構(gòu)體,雙擊該變量,打開詳細棧幀視圖,然后使用Edit?Struct Var(ALT+Q)命令顯示一組已知的結(jié)構(gòu)體

    之后上面結(jié)構(gòu)體數(shù)組匯編變?yōu)?#xff1a;重新格式化之后,IDA認識到,任何對分配給var_8的24個字節(jié)塊的內(nèi)存引用,都必須引用該結(jié)構(gòu)體中的一個字段。如果IDA發(fā)現(xiàn)這樣一個引用,它會盡一切努力,將這個內(nèi)存引用與結(jié)構(gòu)體變量中的一個已定義的字段關(guān)聯(lián)起來

    [cpp]?view plaincopy
  • var_8=?stTest?ptr?-8??
  • ??
  • push????ebp??
  • mov?????ebp,?esp??
  • sub?????esp,?8??
  • push????48??????????????;?unsigned?int??
  • call??????2@YAPAXI@Z????;?operator?new(uint)??
  • add?????esp,?4??
  • mov?????[ebp+var_8.f1],?eax??
  • mov?????eax,?[ebp+var_8.f1]??
  • mov?????dword?ptr?[ebp+var_8.f2],?eax??
  • mov?????ecx,?dword?ptr?[ebp+var_8.f2]??
  • mov?????dword?ptr?[ecx+(size?stTest)],?10??
  • mov?????edx,?20??
  • mov?????eax,?dword?ptr?[ebp+var_8.f2]??
  • mov?????[eax+1Ch],?dx??
  • mov?????ecx,?dword?ptr?[ebp+var_8.f2]??
  • mov?????byte?ptr?[ecx+30],?30??
  • mov?????edx,?dword?ptr?[ebp+var_8.f2]??
  • mov?????[edx+(stTest.f4+18h)],?40??
  • mov?????eax,?dword?ptr?[ebp+var_8.f2]??
  • fld?????ds:dbl_4020F0??
  • fstp????[eax+(stTest.f5+18h)]??
  • mov?????esp,?ebp??
  • pop?????ebp??
  • retn??
  • 將全局變量格式化成結(jié)構(gòu)體的過程與格式化棧變量所使用的過程幾乎完全相同

    導入新的結(jié)構(gòu)體

    在創(chuàng)建新結(jié)構(gòu)體方面,IDA確實提供了一些捷徑。IDA能夠解析C(而非C++)數(shù)據(jù)聲明,以及整個C頭文件,并自動為在這些聲明或頭文件中定義的結(jié)構(gòu)體創(chuàng)建對應(yīng)的IDA結(jié)構(gòu)體。如果你碰巧擁有你正進行逆向工程的二進制文件的源代碼,或者至少是頭文件,那么,你就可以讓IDA直接從源代碼中提取出相關(guān)結(jié)構(gòu)體,從而節(jié)省大量時間。

    使用View?Open Subviews?Local Types(查看?打開子窗口?本地類型)命令,可以打開Local Types子窗口,其中列出了所有解析到當前數(shù)據(jù)庫中的類型。

    通過INSERT鍵或上下文菜單中的Insert選項解析:

    ?------------->

    ?

    ?解析C頭文件

    要解析頭文件,可以使用File?Load File?Parse C HeaderFile(文件?加載文件?解析C頭文件)選擇你想要解析的頭文件。如果一切正常,IDA會通知你Compilation successful(編譯完成)。如果解析器遇到任何問題,IDA將會在輸出窗口中顯示錯誤消息

    IDA會將所有被成功解析的結(jié)構(gòu)體添加到當前數(shù)據(jù)庫的標準結(jié)構(gòu)體列表中(具體地說,是列表的末尾)。如果新結(jié)構(gòu)體的名稱與現(xiàn)有結(jié)構(gòu)體的名稱相同,IDA會用新結(jié)構(gòu)體布局覆蓋原有結(jié)構(gòu)體定義。除非你明確選擇添加新的結(jié)構(gòu)體,否則,新結(jié)構(gòu)體不會出現(xiàn)在Structures窗口中

    ?默認情況下,解析器會建立4字節(jié)對齊的結(jié)構(gòu)體,當然,你可以使用pack改變它

    ??解析器只能理解C標準數(shù)據(jù)類型。但是,解析器還能夠理解預處理器define指令和C typedef語句。因此,如果解析器之前遇到過適當?shù)膖ypedef,它將能夠正確解析unit32_t之類的類型。

    ??如果你沒有源代碼,那么你會發(fā)現(xiàn),使用文本編輯器以C表示法迅速定義一個結(jié)構(gòu)體布局,并解析得到的頭文件或把聲明粘貼為一個新的本地類型,會比使用IDA煩瑣的手動結(jié)構(gòu)體定義工具更加方便。

    添加到Local Types(本地類型)窗口中的數(shù)據(jù)類型不會立即在Structures(結(jié)構(gòu)體)最簡單的方法是在類型上單擊鼠標右鍵,并選擇Synchronize to idb

    使用標準結(jié)構(gòu)體

    IDA能夠識別大量與各種庫和API函數(shù)有關(guān)的數(shù)據(jù)結(jié)構(gòu)。當IDA在反匯編代碼清單中操縱結(jié)構(gòu)體時,它會在Structures窗口中添加相應(yīng)的結(jié)構(gòu)體定義。因此,Structures窗口中顯示的是應(yīng)用于當前二進制文件的已知結(jié)構(gòu)體的子集。除了創(chuàng)建自定義結(jié)構(gòu)體外,你還可以從IDA的已知結(jié)構(gòu)體列表中提取出其他標準結(jié)構(gòu)體,并將其添加到Structures窗口中。

    首先,在Structures窗口中按下IN-SERT鍵。在Create structure/ union對話框中,包含一個Add standard structure(添加標準結(jié)構(gòu)體)按鈕。單擊這個按鈕,IDA將顯示與當前編譯器(在分析階段檢測出來)和文件格式有關(guān)的結(jié)構(gòu)體主列表。這個結(jié)構(gòu)體主列表中還包含通過解析C頭文件添加到數(shù)據(jù)庫中的結(jié)構(gòu)體。

    示例:(分析文件頭)

    默認情況下,在創(chuàng)建后,文件頭不會立即加載到數(shù)據(jù)庫中。但是,如果你在最初創(chuàng)建數(shù)據(jù)庫時選擇Manual load(手動加載)選項,就可以將文件頭加載到數(shù)據(jù)庫中。加載文件頭可確保只有與這些頭部有關(guān)的數(shù)據(jù)類型才出現(xiàn)在數(shù)據(jù)庫中。多數(shù)情況下,文件頭不會以任何形式被格式化,因為通常程序并不會直接引用它們自己的文件頭。因此,分析器也沒有必要對文件頭應(yīng)用結(jié)構(gòu)體模板。

    ?

    對一個PE二進制文件進行一番研究后,你會發(fā)現(xiàn),PE文件的開頭部分是一個名為IMAGE_DOS_HEADER的MS-DOS頭部結(jié)構(gòu)體。另外,IMAGE_DOS_HEADER中的數(shù)據(jù)指向一個IM-AGE_NE_HEADER結(jié)構(gòu)體的位置。

    第一步是添加標準的IMAGE_DOS_HEADER結(jié)構(gòu)體(你可以在打開IMAGE_NT_HEADER結(jié)構(gòu)體的同時添加該結(jié)構(gòu)體)。

    第二步是使用Edit?Struct Var(ALT+Q),將從_Image-Base開始的字節(jié)轉(zhuǎn)換成一個IMAGE_DOS_HEADER結(jié)構(gòu)體

    ?

    總結(jié)

    以上是生活随笔為你收集整理的7.IDA-创建结构体的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。