国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開(kāi)發(fā)設(shè)計(jì) > 正文

PE文件格式詳解(5)

2019-11-17 05:04:21
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友
  預(yù)定義段  一個(gè)Windows NT的應(yīng)用程序典型地?fù)碛?個(gè)預(yù)定義段,它們是.text、.bss、.rdata、.data、.rsrc、.edata、.idata、.pdata和.debug。一些應(yīng)用程序不需要所有的這些段,同樣還有一些應(yīng)用程序?yàn)榱俗约悍欠驳男枰x了更多的段。
這種做法與MS-DOS和Windows 3.1中的代碼段和數(shù)據(jù)段相似。事實(shí)上,應(yīng)用程序定義一個(gè)獨(dú)特的段的方法是使用標(biāo)準(zhǔn)編譯器來(lái)指示對(duì)代碼段和數(shù)據(jù)段的命名,或者使用名稱段編譯器選項(xiàng)-NT——就和Windows 3.1中應(yīng)用程序定義獨(dú)特的代碼段和數(shù)據(jù)段一樣。

  以下是一個(gè)關(guān)于Windows NT PE文件之中一些有趣的公共段的討論。  可執(zhí)行代碼段,.text  Windows 3.1和Windows NT之間的一個(gè)區(qū)別就是Windows NT默認(rèn)的做法是將所有的代碼段(正如它們?cè)赪indows 3.1中所提到的那樣)組成了一個(gè)單獨(dú)的段,名為“.text”。既然Windows NT使用了基于頁(yè)面的虛擬內(nèi)存治理系統(tǒng),那么將分開(kāi)的代碼放入不同的段之中的做法就不太明智了。因此,擁有一個(gè)大的代碼段對(duì)于操作系統(tǒng)和應(yīng)用程序開(kāi)發(fā)者來(lái)說(shuō),都是十分方便的。

  .text段也包含了早先提到過(guò)的入口點(diǎn)。IAT亦存在于.text段之中的模塊入口點(diǎn)之前。(IAT在.text段之中的存在非常有意義,因?yàn)檫@個(gè)表事實(shí)上是一系列的跳轉(zhuǎn)指令,并且它們的跳轉(zhuǎn)目標(biāo)位置是已固定的地址。)當(dāng)Windows NT的可執(zhí)行映像裝載入進(jìn)程的地址空間時(shí),IAT就和每一個(gè)導(dǎo)入函數(shù)的物理地址一同確定了。要在.text段之中查找IAT,裝載器只用將模塊的入口點(diǎn)定位,而IAT恰恰出現(xiàn)于入口點(diǎn)之前。既然每個(gè)入口擁有相同的尺寸,那么向后退查找這個(gè)表的起始位置就很輕易了。  數(shù)據(jù)段,.bss、.rdata、.data  .bss段表示應(yīng)用程序的未初始化數(shù)據(jù),包括所有函數(shù)或源模塊中聲明為static的變量。

  .rdata段表示只讀的數(shù)據(jù),比如字符串文字量、常量和調(diào)試目錄信息。

  所有其它變量(除了出現(xiàn)在棧上的自動(dòng)變量)存儲(chǔ)在.data段之中?;旧?,這些是應(yīng)用程序或模塊的全局變量。  資源段,.rsrc  .rsrc段包含了模塊的資源信息。它起始于一個(gè)資源目錄結(jié)構(gòu),這個(gè)結(jié)構(gòu)就像其它大多數(shù)結(jié)構(gòu)一樣,但是它的數(shù)據(jù)被更進(jìn)一步地組織在了一棵資源樹之中。以下的IMAGE_RESOURCE_DirectorY結(jié)構(gòu)形成了這棵樹的根和各個(gè)結(jié)點(diǎn)。

  WINNT.H
  typedef strUCt _IMAGE_RESOURCE_DIRECTORY {
  ULONG Characteristics;
  ULONG TimeDateStamp;
  USHORT MajorVersion;
  USHORT MinorVersion;
  USHORT NumberOfNamedEntries;
  USHORT NumberOfIdEntries;
  } IMAGE_RESOURCE_DIRECTORY, *PIMAGE_RESOURCE_DIRECTORY;

  請(qǐng)看這個(gè)目錄結(jié)構(gòu),你將會(huì)發(fā)現(xiàn)其中竟然沒(méi)有指向下一個(gè)結(jié)點(diǎn)的指針。但是,在這個(gè)結(jié)構(gòu)中有兩個(gè)域NumberOfNamedEntries和NumberOfIdEntries代替了指針,它們被用來(lái)表示這個(gè)目錄附有多少入口。附帶說(shuō)一句,我的意思是目錄入口就在段數(shù)據(jù)之中的目錄后邊。有名稱的入口按字母升序出現(xiàn),再往后是按數(shù)值升序排列的ID入口。


  一個(gè)目錄入口由兩個(gè)域組成,正如下面IMAGE_RESOURCE_DIRECTORY_ENTRY結(jié)構(gòu)所描述的那樣:
  WINNT.H
  typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY {
  ULONG Name;
  ULONG OffsetToData;
  } IMAGE_RESOURCE_DIRECTORY_ENTRY,    *PIMAGE_RESOURCE_DIRECTORY_ENTRY;

  根據(jù)樹的層級(jí)不同,這兩個(gè)域也就有著不同的用途。Name域被用于標(biāo)識(shí)一個(gè)資源種類,或者一種資源名稱,或者一個(gè)資源的語(yǔ)言ID。OffsetToData與經(jīng)常被用來(lái)在樹之中指向兄弟結(jié)點(diǎn)——即一個(gè)目錄結(jié)點(diǎn)或一個(gè)葉子結(jié)點(diǎn)。

  葉子結(jié)點(diǎn)是資源樹之中最底層的結(jié)點(diǎn),它們定義了當(dāng)前資源數(shù)據(jù)的尺寸和位置。IMAGE_RESOURCE_DATA_ENTRY結(jié)構(gòu)被用于描述每個(gè)葉子結(jié)點(diǎn):

  WINNT.H
  typedef struct _IMAGE_RESOURCE_DATA_ENTRY {
  ULONG OffsetToData;
  ULONG Size;
  ULONG CodePage;
  ULONG Reserved;
  } IMAGE_RESOURCE_DATA_ENTRY, *PIMAGE_RESOURCE_DATA_ENTRY;

  OffsetToData和Size這兩個(gè)域表示了當(dāng)前資源數(shù)據(jù)的位置和尺寸。既然這一信息主要是在應(yīng)用程序裝載以后由函數(shù)使用的,那么將OffsetToData作為一個(gè)相對(duì)虛擬的地址會(huì)更有意義一些?!疑?,恰好是這樣沒(méi)錯(cuò)。
非常有趣的是,所有其它的偏移量,比如從目錄入口到其它目錄的指針,都是相對(duì)于根結(jié)點(diǎn)位置的偏移量。

  要更清楚地了解這些內(nèi)容,請(qǐng)參考圖2。  圖2.一個(gè)簡(jiǎn)單的資源樹結(jié)構(gòu)

  圖2描述了一個(gè)非常簡(jiǎn)單的資源樹,它包含了僅僅兩個(gè)資源對(duì)象:一個(gè)菜單和一個(gè)字串表。更深一層地來(lái)說(shuō),它們各自都有一個(gè)子項(xiàng)。然而,你仍然可以看到資源樹有多么復(fù)雜——即使它像這個(gè)一樣只有一點(diǎn)點(diǎn)資源。

  在樹的根部,第一個(gè)目錄有一個(gè)文件中包含的所有資源種類的入口,而不管資源種類有多少。在圖2中,有兩個(gè)由樹根標(biāo)識(shí)的入口,一個(gè)是菜單的,另一個(gè)是字串表的。假如文件中擁有一個(gè)或多個(gè)對(duì)話框資源,那么根結(jié)點(diǎn)會(huì)再擁有一個(gè)入口,因此,就有了對(duì)話框資源的另一個(gè)分支。

  WINUSER.H中標(biāo)識(shí)了基本的資源種類,我將它們列到了下面:

  WINUSER.H
  /*
  * 預(yù)定義的資源種類
  */
  #define RT_CURSOR MAKEINTRESOURCE(1)
  #define RT_BITMAP MAKEINTRESOURCE(2)
  #define RT_ICON MAKEINTRESOURCE(3)
  #define RT_MENU MAKEINTRESOURCE(4)
  #define RT_DIALOG MAKEINTRESOURCE(5)
  #define RT_STRING MAKEINTRESOURCE(6)
  #define RT_FONTDIR MAKEINTRESOURCE(7)
  #define RT_FONT MAKEINTRESOURCE(8)
  #define RT_ACCELERATOR MAKEINTRESOURCE(9)
  #define RT_RCDATA MAKEINTRESOURCE(10)
  #define RT_MESSAGETABLE MAKEINTRESOURCE(11)

  在樹的第一層級(jí),以上列出的MAKEINTRESOURCE值被放置在每個(gè)種類入口的Name處,它標(biāo)識(shí)了不同的資源種類。

  每個(gè)根目錄的入口都指向了樹中第二層級(jí)的一個(gè)兄弟結(jié)點(diǎn),這些結(jié)點(diǎn)也是目錄,并且每個(gè)都擁有它們自己的入口。在這一層級(jí),目錄被用來(lái)以給定的種類標(biāo)識(shí)每一個(gè)資源種類。假如你的應(yīng)用程序中有多個(gè)菜單,那么樹中的第二層級(jí)會(huì)為每個(gè)菜單都預(yù)備一個(gè)入口。

  你可能意識(shí)到了,資源可以由名稱或整數(shù)標(biāo)識(shí)。在這一層級(jí),它們是通過(guò)目錄結(jié)構(gòu)的Name域來(lái)分辨的。假如假如Name域最重要的位被設(shè)置了,那么其它的31個(gè)位就會(huì)被用作一個(gè)到IMAGE_RESOURCE_DIR_STRING_U結(jié)構(gòu)的偏移量。


  WINNT.H
  typedef struct _IMAGE_RESOURCE_DIR_STRING_U {
  USHORT Length;
  WCHAR NameString[1];
  } IMAGE_RESOURCE_DIR_STRING_U, *PIMAGE_RESOURCE_DIR_STRING_U;

  這個(gè)結(jié)構(gòu)僅僅是由一個(gè)2字節(jié)長(zhǎng)的Length域和一個(gè)UNICODE字符Length組成的。
  另一方面,假如Name域最重要的位被清空,那么它的低31位就被用于表示資源的整數(shù)ID。圖2示范的就是菜單資源作為一個(gè)命名的資源,以及字串表作為一個(gè)ID資源。

  假如有兩個(gè)菜單資源,一個(gè)由名稱標(biāo)識(shí),另一個(gè)由資源標(biāo)識(shí),那么它們二者就會(huì)在菜單資源目錄之后擁有兩個(gè)入口。有名稱的資源入口在第一位,之后是由整數(shù)標(biāo)識(shí)的資源。目錄域NumberOfNamedEntries和NumberOfIdEntries將各自包含值1,表示當(dāng)前的1個(gè)入口。

  在第二層級(jí)的下面,資源樹就不再更深一步地?cái)U(kuò)展分支了。第一層級(jí)分支至表示每個(gè)資源種類的目錄中,第二層級(jí)分支至由標(biāo)識(shí)符表示的每個(gè)資源的目錄中,第三層級(jí)是被個(gè)別標(biāo)識(shí)的資源與它們各自的語(yǔ)言ID之間一對(duì)一的映射。要表示一個(gè)資源的語(yǔ)言ID,目錄入口結(jié)構(gòu)的Name域就被用來(lái)表示資源的主語(yǔ)言ID和子語(yǔ)言ID了。Windows NT的Win32 SDK開(kāi)發(fā)包中列出了默認(rèn)的值資源,例如對(duì)于0x0409這個(gè)值來(lái)說(shuō),0x09表示主語(yǔ)言LANG_ENGLISH,0x04則被定義為子語(yǔ)言的SUBLANG_ENGLISH_CAN。所有的語(yǔ)言ID值都定義于Windows NT Win32 SDK開(kāi)發(fā)包的文件WINNT.H中。

  既然語(yǔ)言ID結(jié)點(diǎn)是樹中最后的目錄結(jié)點(diǎn),那么入口結(jié)構(gòu)的OffsetToData域就是到一個(gè)葉子結(jié)點(diǎn)(即前面提到過(guò)的IMAGE_RESOURCE_DATA_ENTRY結(jié)構(gòu))的偏移量。

  再回過(guò)頭來(lái)參考圖2,你會(huì)發(fā)現(xiàn)每個(gè)語(yǔ)言目錄入口都對(duì)應(yīng)著一個(gè)數(shù)據(jù)入口。這個(gè)結(jié)點(diǎn)僅僅表示了資源數(shù)據(jù)的尺寸以及資源數(shù)據(jù)的相對(duì)虛擬地址。

  在資源數(shù)據(jù)段(.rsrc)之中擁有這么多結(jié)構(gòu)有一個(gè)好處,就是你可以不存取資源本身而直接可以從這個(gè)段收集很多信息。例如,你可以獲得有多少種資源、哪些資源(假如有的話)使用了非凡的語(yǔ)言ID、特定的資源是否存在以及單獨(dú)種類資源的尺寸。
為了示范如何利用這一信息,以下的函數(shù)說(shuō)明了如何決定一個(gè)文件中包含的不同種類的資源:

  PEFILE.C
  int WINAPI GetListOfResourceTypes(LPVOID lpFile, HANDLE hHeap,
    char **pszResTypes)
  {
  PIMAGE_RESOURCE_DIRECTORY PRdRoot;
  PIMAGE_RESOURCE_DIRECTORY_ENTRY prde;
  char *pMem;
  int nCnt, i;
  /* 獲得資源樹的根目錄 */
  if ((prdRoot = (PIMAGE_RESOURCE_DIRECTORY)   ImageDirectoryOffset
      lpFile, IMAGE_DIRECTORY_ENTRY_RESOURCE)) == NULL)
    return 0;
  /* 在堆上分配足夠的空間來(lái)包括所有類型 */
  nCnt = prdRoot->NumberOfIdEntries * (MAXRESOURCENAME + 1);
  *pszResTypes = (char *)HeapAlloc(hHeap, HEAP_ZERO_MEMORY,
      nCnt);
  if ((pMem = *pszResTypes) == NULL)
    return 0;
  /* 將指針指向第一個(gè)資源種類的入口 */
  prde = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)((DWord)prdRoot +
      sizeof (IMAGE_RESOURCE_DIRECTORY));
  /* 在所有的資源目錄入口類型中循環(huán) */
  for (i = 0; i < prdRoot->NumberOfIdEntries; i++)
  {
    if (LoadString(hDll, prde->Name, pMem, MAXRESOURCENAME))
      pMem += strlen(pMem) + 1;
    prde++;
  }
  return nCnt;
  }

  這個(gè)函數(shù)將一個(gè)資源種類名稱的列表寫入了由pszResTypes標(biāo)識(shí)的變量中。
請(qǐng)注重,在這個(gè)函數(shù)的核心部分,LoadString是使用各自資源種類目錄入口的Name域來(lái)作為字符串ID的。假如你查看PEFILE.RC,你會(huì)發(fā)現(xiàn)我定義了一系列的資源種類的字符串,并且它們的ID與它們?cè)谀夸浫肟谥械亩x完全相同。PEFILE.DLL還有有一個(gè)函數(shù),它返回了.rsrc段中的資源對(duì)象總數(shù)。這樣一來(lái),從這個(gè)段中提取其它的信息,借助這些函數(shù)或另外編寫函數(shù)就方便多了。(未完待續(xù))

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 社会| 华坪县| 札达县| 岳阳县| 威远县| 芮城县| 永登县| 弥渡县| 淳安县| 广平县| 土默特右旗| 诏安县| 长沙县| 广宁县| 上林县| 赤壁市| 偃师市| 辉县市| 都昌县| 黄大仙区| 忻城县| 富阳市| 汪清县| 连山| 友谊县| 威海市| 万州区| 迁西县| 怀安县| 海淀区| 北辰区| 顺平县| 基隆市| 古蔺县| 南雄市| 青铜峡市| 临清市| 漾濞| 江阴市| 宜城市| 岳池县|