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

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

PE文件格式詳解(4)

2019-11-17 05:04:19
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友
  PE文件段
  PE文件規(guī)范由目前為止定義的那些頭部以及一個(gè)名為“段”的一般對(duì)象組成。段包含了文件的內(nèi)容,包括代碼、數(shù)據(jù)、資源以及其它可執(zhí)行信息,每個(gè)段都有一個(gè)頭部和一個(gè)實(shí)體(原始數(shù)據(jù))。我將在下面描述段頭部的有關(guān)信息,但是段實(shí)體則缺少一個(gè)嚴(yán)格的文件結(jié)構(gòu)。因此,它們幾乎可以被鏈接器按任何的方法組織,只要它的頭部填充了足夠能夠解釋數(shù)據(jù)的信息。   段頭部   PE文件格式中,所有的段頭部位于可選頭部之后。每個(gè)段頭部為40個(gè)字節(jié)長(zhǎng),并且沒(méi)有任何的填充信息。段頭部被定義為以下的結(jié)構(gòu):

  WINNT.H
  #define IMAGE_SIZEOF_SHORT_NAME 8
  typedef strUCt _IMAGE_SECTION_HEADER {
  UCHAR Name[IMAGE_SIZEOF_SHORT_NAME];
  union {
    ULONG PhysicalAddress;
    ULONG VirtualSize;
  } Misc;
  ULONG VirtualAddress;
  ULONG SizeOfRawData;
  ULONG PointerToRawData;
  ULONG PointerToRelocations;
  ULONG PointerToLinenumbers;
  USHORT NumberOfRelocations;
  USHORT NumberOfLinenumbers;
  ULONG Characteristics;
  } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

  你如何才能獲得一個(gè)特定段的段頭部信息?既然段頭部是被連續(xù)的組織起來(lái)的,而且沒(méi)有一個(gè)特定的順序,那么段頭部必須由名稱(chēng)來(lái)定位。以下的函數(shù)示范了如何從一個(gè)給定了段名稱(chēng)的PE映像文件中獲得一個(gè)段頭部:

  PEFILE.C
  BOOL WINAPI GetSectionHdrByName(LPVOID lpFile,
    IMAGE_SECTION_HEADER *sh, char *szSection)
  {
  PIMAGE_SECTION_HEADER psh;
  int nSections = NumOfSections (lpFile);
  int i;
  if ((psh = (PIMAGE_SECTION_HEADER)SECHDROFFSET(lpFile))
      != NULL)
    {
    /* 由名稱(chēng)查找段 */
    for (i = 0; i < nSections; i++)
    {
      if (!strcmp(psh->Name, szSection))
      {
        /* 向頭部復(fù)制數(shù)據(jù) */
        CopyMemory((LPVOID)sh, (LPVOID)psh,
            sizeof(IMAGE_SECTION_HEADER));
        return TRUE;
      }
      else
        psh++;

    }
  }
  return FALSE;
  }

  這個(gè)函數(shù)通過(guò)SECHDROFFSET宏將第一個(gè)段頭部定位,然后它開(kāi)始在所有段中循環(huán),并將要尋找的段名稱(chēng)和每個(gè)段的名稱(chēng)相比較,直到找到了正確的那一個(gè)為止。當(dāng)找到了段的時(shí)候,函數(shù)將內(nèi)存映像文件的數(shù)據(jù)復(fù)制到傳入函數(shù)的結(jié)構(gòu)中,然后IMAGE_SECTION_HEADER結(jié)構(gòu)的各域就能夠被直接存取了。     段頭部的域   ·Name。每個(gè)段都有一個(gè)8字符長(zhǎng)的名稱(chēng)域,并且第一個(gè)字符必須是一個(gè)句點(diǎn)。
  ·PhysicalAddress或VirtualSize。第二個(gè)域是一個(gè)union域,現(xiàn)在已不使用了。

  ·VirtualAddress。這個(gè)域標(biāo)識(shí)了進(jìn)程地址空間中要裝載這個(gè)段的虛擬地址。實(shí)際的地址由將這個(gè)域的值加上可選頭部結(jié)構(gòu)中的ImageBase虛擬地址得到。切記,假如這個(gè)映像文件是一個(gè)DLL,那么這個(gè)DLL就不一定會(huì)裝載到ImageBase要求的位置。所以一旦這個(gè)文件被裝載進(jìn)入了一個(gè)進(jìn)程,實(shí)際的ImageBase值應(yīng)該通過(guò)使用GetModuleHandle來(lái)檢驗(yàn)。

  ·SizeOfRawData。這個(gè)域表示了相對(duì)FileAlignment的段實(shí)體尺寸。文件中實(shí)際的段實(shí)體尺寸將少于或等于FileAlignment的整倍數(shù)。一旦映像被裝載進(jìn)入了一個(gè)進(jìn)程的地址空間,段實(shí)體的尺寸將會(huì)變得少于或等于FileAlignment的整倍數(shù)。
  ·PointerToRawData。這是一個(gè)文件中段實(shí)體位置的偏移量。

  ·PointerToRelocations、PointerToLinenumbers、NumberOfRelocations、NumberOfLinenumbers。這些域在PE格式中不使用。

  ·Characteristics。定義了段的特征。這些值可以在WINNT.H及本光盤(pán)(譯注:MSDN的光盤(pán))的PE格式規(guī)范中找到。

定義0x00000020代碼段0x00000040已初始化數(shù)據(jù)段0x00000080未初始化數(shù)據(jù)段0x04000000該段數(shù)據(jù)不能被緩存0x08000000該段不能被分頁(yè)0x10000000共享段0x20000000可執(zhí)行段0x40000000可讀段0x80000000可寫(xiě)段  定位數(shù)據(jù)目錄  數(shù)據(jù)目錄存在于它們相應(yīng)的數(shù)據(jù)段中。典型地來(lái)說(shuō),數(shù)據(jù)目錄是段實(shí)體中的第一個(gè)結(jié)構(gòu),但不是必需的。由于這個(gè)緣故,假如你需要定位一個(gè)指定的數(shù)據(jù)目錄的話,就需要從段頭部和可選頭部中獲得信息。

  為了讓這個(gè)過(guò)程簡(jiǎn)單一點(diǎn),我編寫(xiě)了以下的函數(shù)來(lái)定位任何一個(gè)在WINNT.H之中定義的數(shù)據(jù)目錄。

  PEFILE.C
  LPVOID WINAPI ImageDirectoryOffset(LPVOID lpFile,
    DWord dwIMAGE_DIRECTORY)
  {
  PIMAGE_OPTIONAL_HEADER poh;
  PIMAGE_SECTION_HEADER psh;
  int nSections = NumOfSections(lpFile);
  int i = 0;
  LPVOID VAImageDir;
  /* 必須為0到(NumberOfRvaAndSizes-1)之間 */
  if (dwIMAGE_DIRECTORY >= poh->NumberOfRvaAndSizes)
    return NULL;
  /* 獲得可選頭部和段頭部的偏移量 */
  poh = (PIMAGE_OPTIONAL_HEADER)OPTHDROFFSET(lpFile);
  psh = (PIMAGE_SECTION_HEADER)SECHDROFFSET(lpFile);
  /* 定位映像目錄的相對(duì)虛擬地址 */
  VAImageDir = (LPVOID)poh->DataDirectory
      [dwIMAGE_DIRECTORY].VirtualAddress;
  /* 定位包含映像目錄的段 */
  while (i++ < nSections)
  {
    if (psh->VirtualAddress <= (DWORD)VAImageDir &&
        psh->VirtualAddress +

        psh->SizeOfRawData > (DWORD)VAImageDir)
      break;
    psh++;
  }
  if (i > nSections)
    return NULL;
  /* 返回映像導(dǎo)入目錄的偏移量 */
  return (LPVOID)(((int)lpFile +
      (int)VAImageDir. psh->VirtualAddress) +
      (int)psh->PointerToRawData);
  }

  該函數(shù)首先確認(rèn)被請(qǐng)求的數(shù)據(jù)目錄入口數(shù)字,然后它分別獲取指向可選頭部和第一個(gè)段頭部的兩個(gè)指針。它從可選頭部決定數(shù)據(jù)目錄的虛擬地址,然后它使用這個(gè)值來(lái)決定數(shù)據(jù)目錄定位在哪個(gè)段實(shí)體之中。假如適當(dāng)?shù)亩螌?shí)體已經(jīng)被標(biāo)識(shí)了,那么數(shù)據(jù)目錄特定的位置就可以通過(guò)將它的相對(duì)虛擬地址轉(zhuǎn)換為文件中地址的方法來(lái)找到。(未完待續(xù))

發(fā)表評(píng)論 共有條評(píng)論
用戶(hù)名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 左云县| 花垣县| 綦江县| 固阳县| 齐河县| 威海市| 康保县| 开平市| 邢台市| 沧源| 乌拉特后旗| 南投县| 崇阳县| 商洛市| 常州市| 河南省| 新兴县| 吴堡县| 鄯善县| 宁蒗| 蓝田县| 双柏县| 名山县| 大丰市| 辽源市| 大埔县| 鄯善县| 镇赉县| 南召县| 新宾| 亚东县| 隆化县| 建阳市| 葵青区| 兴安盟| 旌德县| 油尖旺区| 禹州市| 喀喇| 扶余县| 南通市|