new 一个结构体数组_每天一个IDA小技巧(四):结构体识别
之前提到IDA可以將一長串的數(shù)組數(shù)據(jù)聲明變成一行數(shù)組聲明,簡化反匯編代碼,對(duì)于結(jié)構(gòu)體,IDA也同樣支持通過各種設(shè)置工具來改善結(jié)構(gòu)體代碼的可讀性。
這篇文章的目標(biāo)是將[edx+10h]之類的結(jié)構(gòu)體元素訪問 變成 [edx+struct_filed5]之類。
只要發(fā)現(xiàn)一個(gè)程序正操縱某種數(shù)據(jù)結(jié)構(gòu),你就需要確定:你是否希望將結(jié)構(gòu)體的字段名稱合并到反匯編代碼清單中,或者你是否理解分散在代碼清單中的所有數(shù)字偏移量。
如果是C標(biāo)準(zhǔn)庫或者IDA能夠確定的已知結(jié)構(gòu)體,IDA會(huì)自動(dòng)將數(shù)字偏移量轉(zhuǎn)換成更加符號(hào)化的字段名稱,但如果是自定義的結(jié)構(gòu)體,就需要我們手動(dòng)幫助IDA進(jìn)行識(shí)別。
IDA之所以在分析階段無法識(shí)別結(jié)構(gòu)體,可能源于兩個(gè)原因。首先,雖然IDA了解某個(gè)結(jié)構(gòu)體的布局,但它并沒有足夠的信息,能夠判斷程序確實(shí)使用了結(jié)構(gòu)體。其次,程序中的結(jié)構(gòu)體可能是一種IDA對(duì)其一無所知的非標(biāo)準(zhǔn)結(jié)構(gòu)體。在這兩種情況下,問題都可以得到解決,且首先從Structures窗口下手。
創(chuàng)建一個(gè)新的結(jié)構(gòu)體(或Union)
在IDA Structures窗口(默認(rèn)展示,如果沒有可以在View -> Open SubViews里打開)中,列舉了當(dāng)前反匯編文件的所有已知結(jié)構(gòu)體,并且在注釋中也提示了我們?nèi)绾卧谠摯翱谥刑砑?刪除/編輯一個(gè)結(jié)構(gòu)體:
00000000 ; Ins/Del : create/delete structure 或者 Edit -> Add struct type
00000000 ; D/A/* : create structure member (data/ascii/array)
00000000 ; N : rename structure or structure member
00000000 ; U : delete structure member
注意:只有當(dāng)一個(gè)字段是結(jié)構(gòu)體中的最后一個(gè)字段時(shí),使用U鍵才能刪除該字段。對(duì)于所有其他字段,按下U鍵將取消該字段的定義,這樣做僅僅刪除了該字段的名稱,并沒有刪除分配給該字段的字節(jié)。
為了創(chuàng)建一個(gè)新的結(jié)構(gòu)體,你必須首先在Structure name(結(jié)構(gòu)體名稱)字段中指定結(jié)構(gòu)體的名稱。前兩個(gè)復(fù)選框用于決定新結(jié)構(gòu)體在Structures窗口中的顯示位置,或者是否在窗口中顯示新結(jié)構(gòu)體。第三個(gè)復(fù)選框Creat union(創(chuàng)建聯(lián)合),指定你定義的是否為C風(fēng)格聯(lián)合結(jié)構(gòu)體(Union和結(jié)構(gòu)體的區(qū)別在于union中字段相互重疊,因此總大小等于其中最大字段的大小)。
此外還有一個(gè)按鈕「add standard structure」,用于添加標(biāo)準(zhǔn)結(jié)構(gòu)體。IDA內(nèi)置了大量的各種庫和API函數(shù)有關(guān)的數(shù)據(jù)結(jié)構(gòu),IDA會(huì)嘗試確定與二進(jìn)制文件有關(guān)的編譯器和平臺(tái),并加載適當(dāng)?shù)慕Y(jié)構(gòu)體模板。單擊這個(gè)按鈕,IDA將顯示與當(dāng)前編譯器(在分析階段檢測出來)和文件格式有關(guān)的結(jié)構(gòu)體主列表。這個(gè)結(jié)構(gòu)體主列表中還包含通過解析C頭文件添加到數(shù)據(jù)庫中的結(jié)構(gòu)體。
編輯結(jié)構(gòu)體成員
為了給新結(jié)構(gòu)體添加字段,你必須利用字段創(chuàng)建命令D、A和數(shù)字鍵盤上的星號(hào)鍵(*),需要注意的是D快捷鍵還可用于為當(dāng)前光標(biāo)所所在的字段調(diào)整數(shù)據(jù)大小。所以推薦的創(chuàng)建結(jié)構(gòu)體的步驟為:
在結(jié)構(gòu)體定義的最后一行(包含ends的那一行)按下D鍵,這時(shí)候,IDA會(huì)在結(jié)構(gòu)體末尾添加一個(gè)新字段,默認(rèn)的字段名稱為filed_N,N為結(jié)構(gòu)體開頭到字段開頭的數(shù)字偏移量。
如果需要修改字段大小,可以重復(fù)按D,循環(huán)數(shù)據(jù)轉(zhuǎn)盤上的數(shù)據(jù)類型,或者通過Options->Setup Data Types來指定一個(gè)在數(shù)據(jù)轉(zhuǎn)盤上不存在的大小,如果是數(shù)組,右鍵名稱然后選擇Array。
如果要更改字段名稱,使用N或者右鍵然后Rename
如果知道結(jié)構(gòu)體的大小,而不了解它的布局,你需要?jiǎng)?chuàng)建兩個(gè)字段。第一個(gè)字段為一個(gè)數(shù)組,它的大小為結(jié)構(gòu)體的大小減去1個(gè)字節(jié)(size-1);第二個(gè)字段應(yīng)為1個(gè)字節(jié)。創(chuàng)建第二個(gè)字段后,取消第一個(gè)(數(shù)組)字段的定義。這樣,結(jié)構(gòu)體的大小被保留下來,隨后,當(dāng)你進(jìn)一步了解該結(jié)構(gòu)體的布局后,你可以回過頭來定義它的字段及其大小。
此外,在你定義和編輯結(jié)構(gòu)體時(shí),IDA會(huì)有一些提示:
一個(gè)字段的字節(jié)偏移量以一個(gè)8位十六進(jìn)制值在Structures窗口的左側(cè)顯示。
每次你添加或刪除一個(gè)結(jié)構(gòu)體字段,或更改一個(gè)現(xiàn)有字段的大小時(shí),結(jié)構(gòu)體的新大小都會(huì)在結(jié)構(gòu)體定義的第一行反映出來。
你必須對(duì)一個(gè)結(jié)構(gòu)體定義中的所有字段進(jìn)行適當(dāng)?shù)膶?duì)齊。如果你需要填補(bǔ)字節(jié),那么你必須負(fù)責(zé)添加這些字節(jié)。填補(bǔ)字節(jié)最好作為適當(dāng)大小的啞字段添加。
分配到結(jié)構(gòu)體中間的字節(jié)只有在取消關(guān)聯(lián)字段的定義后才能刪除,使用Edit?Shrink Struct Type(縮小結(jié)構(gòu)體類型)即可刪除被取消定義的字節(jié)。
你也可以在結(jié)構(gòu)體的中間添加新的字節(jié):選擇新字節(jié)后面的一個(gè)字段,然后使用Edit?Expand Struct Type(擴(kuò)大結(jié)構(gòu)體類型)在選中的字段前插入一定數(shù)量的字節(jié)。
通過重復(fù)應(yīng)用這些步驟(添加字段,設(shè)置字段大小,添加填補(bǔ)字節(jié)等),就可以完成IDA結(jié)構(gòu)體定義的創(chuàng)建。接下來就可以利用這些定義好的結(jié)構(gòu)體改善反匯編代碼。
使用結(jié)構(gòu)體模版
前面提到這篇文章的目標(biāo)是將[edx+10h]之類的結(jié)構(gòu)體元素訪問 變成 [edx+struct_filed5]之類。
此時(shí)有了結(jié)構(gòu)體定義之后,就可以右鍵10h,選擇Structure Offset(結(jié)構(gòu)體偏移量)選項(xiàng),然后就可以進(jìn)行格式化了,如果有多個(gè)結(jié)構(gòu)體中字段匹配上了偏移量,則會(huì)有多個(gè)選擇。
如果是棧變量或者全局變量,則可以直接將棧和全局變量格式化為整個(gè)結(jié)構(gòu)體,首先打開棧幀的詳細(xì)視圖(雙擊函數(shù)棧幀中的變量),然后使用ALT+Q(Edit->Struct Var)命令顯示一組已知的結(jié)構(gòu)體并選擇對(duì)應(yīng)想要格式化的結(jié)構(gòu)體即可。如果是全局變量,則選擇要格式化的全局變量或者表示結(jié)構(gòu)體開頭部分的地址,再使用ALT+Q(Edit->Struct Var)即可。
重新格式化之后,IDA認(rèn)識(shí)到,任何對(duì)分配給var_18的24個(gè)字節(jié)塊的內(nèi)存引用,都必須引用該結(jié)構(gòu)體中的一個(gè)字段。如果IDA發(fā)現(xiàn)這樣一個(gè)引用,它會(huì)盡一切努力,將這個(gè)內(nèi)存引用與結(jié)構(gòu)體變量中的一個(gè)已定義的字段關(guān)聯(lián)起來。
導(dǎo)入結(jié)構(gòu)體
IDA能夠解析C(而非C++)數(shù)據(jù)聲明,以及整個(gè)C頭文件,并自動(dòng)為在這些聲明或頭文件中定義的結(jié)構(gòu)體創(chuàng)建對(duì)應(yīng)的IDA結(jié)構(gòu)體。如果你碰巧擁有你正進(jìn)行逆向工程的二進(jìn)制文件的源代碼,或者至少是頭文件,那么,你就可以讓IDA直接從源代碼中提取出相關(guān)結(jié)構(gòu)體,從而節(jié)省大量時(shí)間。
解析C結(jié)構(gòu)體聲明
如果我們已經(jīng)有某個(gè)結(jié)構(gòu)體的聲明代碼,那可以直接在View?Open Subviews?Local Types(查看?打開子窗口?本地類型)窗口中,輸入我們的結(jié)構(gòu)體聲明代碼,例如:
注意,IDA解析器使用4字節(jié)的默認(rèn)結(jié)構(gòu)體成員對(duì)齊方式。如果你的結(jié)構(gòu)體需要其他對(duì)齊方式,你可以包括該對(duì)齊方式,IDA認(rèn)可使用pragma pack指令來指定所需的結(jié)構(gòu)體成員對(duì)齊方式。
添加到Local Types(本地類型)窗口中的數(shù)據(jù)類型不會(huì)立即在Structures(結(jié)構(gòu)體)窗口中出現(xiàn)。有兩種方法可以將本地類型聲明添加到Structures窗口中。最簡單的方法是在相關(guān)本地類型上單擊鼠標(biāo)右鍵,并選擇Synchronize to idb。或者,由于每個(gè)新類型均被添加到標(biāo)準(zhǔn)結(jié)構(gòu)體列表中,因而也可將新類型導(dǎo)入到Structures窗口中即add standard structure。
解析C頭文件
要解析頭文件,可以使用File?Load File?Parse C Header File(文件?加載文件?解析C頭文件)選擇你想要解析的頭文件。如果一切正常,IDA會(huì)通知你Compilation successful(編譯完成)。如果解析器遇到任何問題,IDA將會(huì)在輸出窗口中顯示錯(cuò)誤消息。
IDA會(huì)將所有被成功解析的結(jié)構(gòu)體添加到當(dāng)前數(shù)據(jù)庫的標(biāo)準(zhǔn)結(jié)構(gòu)體列表末尾,此時(shí)同樣需要手動(dòng)從標(biāo)準(zhǔn)結(jié)構(gòu)體列表中添加到Structures窗口中。如果新結(jié)構(gòu)體的名稱與現(xiàn)有結(jié)構(gòu)體的名稱相同,IDA會(huì)用新結(jié)構(gòu)體布局覆蓋原有結(jié)構(gòu)體定義。
一般而言,要最大限度地提高成功解析一個(gè)頭文件的幾率,你需要使用標(biāo)準(zhǔn)C數(shù)據(jù)類型,并盡可能地減少使用include文件,從而最大程度地簡化結(jié)構(gòu)體定義。記住,在IDA中創(chuàng)建結(jié)構(gòu)體時(shí),正確布局最為重要。正確的布局更多地取決于每個(gè)字段的正確大小和結(jié)構(gòu)體的正確對(duì)齊,而不只是對(duì)每個(gè)字段都使用正確的類型。
IDA TIL文件(Type Library)
IDA中的所有數(shù)據(jù)類型和函數(shù)原型信息都存儲(chǔ)在TIL文件中。IDA擁有存儲(chǔ)在/til目錄中的許多主要編譯器和API的類型庫信息。Types窗口(View?Open subview?Type Libraries)列出了當(dāng)前加載的.til文件,并可用于加載你想要使用的其他.til文件。IDA將根據(jù)在分析階段發(fā)現(xiàn)的二進(jìn)制文件屬性,自動(dòng)加載類型庫。正常情況下,一般不需要直接處理.til文件。
IDA還利用.til文件存儲(chǔ)你在Structures窗口中手動(dòng)創(chuàng)建的或者通過解析C頭文件獲得的任何自定義結(jié)構(gòu)體定義。這些結(jié)構(gòu)體存儲(chǔ)在一個(gè)與創(chuàng)建它們的數(shù)據(jù)庫有關(guān)的專用.til文件中。該文件的名稱與其相關(guān)數(shù)據(jù)庫的名稱相同,擴(kuò)展名為.til。
例如,如果數(shù)據(jù)庫名為some_file.idb,則相應(yīng)的類型庫文件則為some_file.til。
.idb文件實(shí)際上是一個(gè)歸檔文件(類似于.tar文件),用于保存不使用的數(shù)據(jù)庫組件。打開一個(gè)數(shù)據(jù)庫時(shí),其組件文件(.til文件為其中之一)將被提取出來,成為IDA中的運(yùn)行文件。
在其他數(shù)據(jù)庫中共享til文件
有兩種共享方法。第一種方法有些不太正規(guī),即將.til文件由打開的數(shù)據(jù)庫復(fù)制到另一個(gè)目錄中,然后再通過Types窗口,在任何其他數(shù)據(jù)庫中打開這個(gè).til文件。第二種是一種正式的方法,即從一個(gè)數(shù)據(jù)庫中提取出自定義類型信息,生成一段IDC腳本,用于在任何其他數(shù)據(jù)庫中重建自定義結(jié)構(gòu)體。使用File?Produce File?Dump Type. into to IDC File(文件?生成文件?轉(zhuǎn)儲(chǔ)類型信息到IDC文件)命令可生成該腳本。但是,與第一種方法不同的是,這種方法只能轉(zhuǎn)儲(chǔ)Structures窗口中列出的結(jié)構(gòu)體,但并不轉(zhuǎn)儲(chǔ)通過解析C頭文件得到的結(jié)構(gòu)體(而復(fù)制.til文件卻可以轉(zhuǎn)儲(chǔ)這類結(jié)構(gòu)體)。
總結(jié)
以上是生活随笔為你收集整理的new 一个结构体数组_每天一个IDA小技巧(四):结构体识别的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java finalize 何时被调用_
- 下一篇: 树叶贴画机器人_洪山广场举办“落叶节”,