小甲魚PE詳解之輸入表(導入表)詳解(PE詳解07)

捷徑並非把彎路改直了,而是幫你把岔道堵上!
走得彎路跟成長的速度是成正比的!不要懼怕走上彎路,彎路會讓你懂得更多,最終仍是會在終點交匯!
岔路會將你引入萬劫不復的深淵,並越走越深……


在開始講解輸入表(導入表)概念以前,請容許小甲魚童鞋用簡短的幾句話來總結以前咱們學過的內容,並作進一步的思想綜合提高,注意咯!

首先,咱們知道PE 文件中的數據被載入內存後根據不一樣頁面屬性被劃分紅不少區塊(節),並有區塊表(節表)的數據來描述這些區塊。這裏咱們須要注意的問題是:一個區塊中的數據僅僅只是因爲屬性相同而放在一塊兒,並不必定是同一種用途的內容。例如接着要講的輸入表、輸出表等就有可能和只讀常量一塊兒被放在同一個區塊中,由於他們的屬性都是可讀不可寫的。

其次,因爲不一樣用途的數據有可能被放入同一個區塊中,所以僅僅依靠區塊表是沒法肯定和定位的。那要怎麼辦?對了,PE 文件頭中 IMAGE_OPTIONAL_DEADER32 結構的數據目錄表來指出他們的位置,咱們能夠由數據目錄表來定位的數據包括輸入表、輸出表、資源、重定位表和TLS等15 種數據。(數據目錄表,不要覺得他在前邊出現就不重要哦~)

這節課咱們談的是輸入表,爲何須要輸入表呢?由於咱們從數據目錄表獲得的僅僅是一些指定數據的RVA 和數據塊的尺寸,很明顯,不一樣的數據塊中的數據組織方式(結構)是顯然不一樣的,例如輸入表和資源數據塊中的數據就徹底是牛馬不相及的兩個東西。所以,咱們 想要深刻了解PE 文件就必須瞭解這些數據的組織方式,以及瞭解系統是如何處理調用它們的。


輸入函數

在代碼分析或編程中常常遇到「輸入函數(Import Functions,也稱導入函數)」的概念。這裏咱們就來解釋下,輸入函數就是被程序調用但其執行代碼又不在程序中的函數,這些函數的代碼位於相關的 DLL 文件中,在調用者程序中只保留相關的函數信息(如函數名、DLL 文件名等)就能夠。對於磁盤上的PE 文件來講,它沒法得知這些輸入函數在內存中的地址,只有當PE 文件被裝入內存後,Windows 加載器纔將相關DLL 裝入,並將調用輸入函數的指令和函數實際所處的地址聯繫起來。這就是「動態連接」的概念。動態連接是經過PE 文件中定義的「輸入表」來完成的,輸入表中保存的正是函數名和其駐留的DLL 名等。


實例預演(視頻中將演示,這裏只能截圖)

之因此是預演,主要是由於咱還沒對輸入表進行解剖前就來給你們演示一下嚐嚐鮮找找滋味~否則學習老是無趣的和鬱悶的~(參與演示的例子程序和工具均可以到解密系列課件與源代碼下載區 找到對應的帖子下載,也能夠看咱視頻演示:解密系列視頻講座 )


以上是咱此次實驗的小青蛙哈~灰常簡單的一個小程序,如圖雙擊程序只顯示一個對話窗口,而後就結束~試驗用小程序,咱們儘可能的將內部的結構刪減,調試起來才方便些。咱們此次體驗的目的就是想靠所學的知識,試圖來找到MessageBox 在內存中的地址。

注:MessageBox 是來自於USER32.DLL 動態連接庫裏的一個函數,咱們經過對PE 文件的靜態反編譯分析來觀察hello.exe 這個試驗品是如何定位和調用MessageBox 這個在「異鄉」的函數哈。
(MessageBox 有兩個版本,一個是MessageBoxA 還有一個是MessageBoxW 分別帶便ASCII碼形式和UNICODE~歷史故事了~)

體驗開始:
1. 咱們用曾經號稱爲屠龍刀的W32DAM 對hello.exe進行反編譯,如圖:



咱們能夠看到這個程序只有兩個導入模塊(Import Module),分別導入來自兩個動態連接庫(USER32.DLL和KERNEL32.DLL)的若干函數,咱們還清晰可見,咱要跟蹤的 MessageBoxA 就在USER32.DLL 中,這裏程序還自動給咱們定位了它的虛擬地址:2A2DC,但咱們不要用這個,由於咱們說過這回咱們是來探險的,凡事講究人工……

咱們經過W32DASM 的查找功能找出MessageBox 這個函數代碼的位置,並試圖查看他的彙編跳轉~
爲啥,這要從彙編調用子程序提及啦~簡單的說就是彙編語言要調用子程序會運用到CALL 和 RET這樣的搭配來進行,學過咱《零基礎入門學習彙編語言》的童鞋還記得小甲魚當時的動畫片演示吧?!上圖……



各位看官看到了吧?push xxxx   push xxxx   push xxxx   push xxxx 以後再來一個Call xxxx ……
沒錯,這就是調用函數的一個標準形式。每一個push 其實就是將所要調用的函數須要的參數入棧,爲啥要入棧呢?這又要從地球的起源提及了……我這裏就簡單的說下吧:棧的發明,使得函數和子程序的出現成爲可 能!對於局部變量和參數,棧的特性最適合不過~不明白不急哈,這個是彙編語言和編譯原理的範疇了,之後咱學習深刻天然會碰到,到時候再來詳細解決就能夠。

int MessageBox( HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType // style of message box );
由定義可見MessageBox 函數共有四個參數,所以咱們四次push xxxx 分別將參數按照STDCALL 的方式入棧以後,就能夠CALL MessageBox 這個函數了。好,既然是CALL 咱們的目標函數了,經過反彙編咱們就能夠觀察到它的地址是:[0042A2AC],難道就這麼簡單?42A2AC 就是目標函數的地址?

那咱們就直接把程序往下拉,試圖找找這個 42A2AC 的地址吧~
但是…… ……


咱們悲劇的發覺,程序壓根還沒到 42A2AC 這地方,到了421FF8 就結束了!!什麼狀況呢?
或許……或許……或許……在沒詳細講輸入表時咱們還不能直接給你們答案……

好吧,小甲魚這裏提問一下,這是一個什麼地址呢?偏移地址 or 虛擬地址?

恩, 沒錯,這是一個VA 哈,那這個VA 上節課咱們說過能夠換算成存放在實際物理內存上的方法。具體就是將這個VA 與該程序的各個區塊的VA 地址逐一對比,因爲PE 頭文件有記載每一個區塊的VA 地址也同時記載着它的實際物理地址,所以咱們能夠經過判斷該VA 位於哪一個區塊內並求出與區塊VA 的差值進而求出該VA 的實際物理地址。那既然前邊直直的路子走不通,咱們就試下把他轉換爲物理地址試試吧?!

好吧,我知道我說話又繞口令了,咱就實例演示下,否則你們要噴了……上圖……



咱們看到,咱的42A2AC 地址加載咱的2A000 和 2B000 之間(改程序VC編寫,映像基地址爲400000打頭哦~),所以咱們能夠將該地址定位到改程序位於.idata 區塊內。該區塊的VA 起始地址爲42A000,所以42A2AC - 42A000 = 2AC,raw data offs 跟咱們說該區塊的物理地址是28000,所以42A2AC 這個VA 所對應的物理偏移地址就是 28000 + 2AC = 282AC。

咱用UE 打開看下282AC 這偏移地址上有啥東西……



282AC 這個地址上存放着 DCA20200 這個數據,翻譯成ASCII 碼也是莫名其妙的說~
但咱們把DCA20200 當成一個DWORD 類型的數據來讀的話咱們獲得數據 0002A2DC(還記得大端與小端吧)
慢着,是否是很熟悉,又是2A****開頭,跟咱以前的地址是否是差很少?那好,咱們又按照剛纔的方法轉化爲偏移地址試試,轉化後獲得的偏移地址是:282DC,咱再看看282DC 裏邊有啥神祕的東西吧?

哈哈,看到奇蹟了嗎?從282DC 地址讀起,ASCII 碼對應的值是MessageBoxA.USER32.dll  怎麼樣,有點神祕的成就感吧~ 但根本問題咱們仍是沒能解決:MessageBox 的地址是?其實在這裏咱們還不能幫你們解決這個問題,由於咱們缺少對輸入表的深刻理解,因此咱們期待吧,下節課將揭開輸入表的神祕面紗……
相關文章
相關標籤/搜索