一段仿真PE加載器行爲的程序

標 題: 【原創】一段仿真PE加載器行爲的程序
作 者: linxer
時 間: 2006-06-10,00:50
鏈 接: http://bbs.pediy.com/showthread.php?threadid=27134

【  標題  】 一段仿真PE加載器行爲的程序
【  聲明  】 水平有限,不對之處敬請各位大俠賜教!

以下程序假定PE文件是合法的,所以很多地方都沒有提供容錯處理

bool PELoader(char *lpStaticPEBuff, long lStaticPELen)
{
  long lPESignOffset = *(long *)(lpStaticPEBuff + 0x3c);
  IMAGE_NT_HEADERS *pINH = (IMAGE_NT_HEADERS *)(lpStaticPEBuff + lPESignOffset);

  //取加載到內存中大小
  long lImageSize = pINH->OptionalHeader.SizeOfImage;
  char *lpDynPEBuff = new char[lImageSize];
  if(lpDynPEBuff == NULL)
  {
    return false;
  }
  memset(lpDynPEBuff, 0, lImageSize);

  //取PE文件的節數量
  long lSectionNum = pINH->FileHeader.NumberOfSections;

  //計算PE頭信息及節表信息佔用內存大小
  long lPEHeadSize = lPESignOffset + sizeof(IMAGE_NT_HEADERS) + lSectionNum * sizeof(IMAGE_SECTION_HEADER);
  
  //加載PE頭部信息及其各個節表
  memcpy(lpDynPEBuff, lpStaticPEBuff, lPEHeadSize);

  //加載各個節
  long lFileAlignMask = pINH->OptionalHeader.FileAlignment - 1;        //各節在磁盤中的對齊掩碼
  long lSectionAlignMask = pINH->OptionalHeader.SectionAlignment - 1;  //各節在load後內存中的對齊掩碼
  IMAGE_SECTION_HEADER *pISH = (IMAGE_SECTION_HEADER *)((char *)pINH + sizeof(IMAGE_NT_HEADERS));
  for(int nIndex = 0; nIndex < lSectionNum; nIndex++, pISH++)
  {
    //判定各節的對齊屬性,合法不
    if((pISH->VirtualAddress & lSectionAlignMask) || (pISH->SizeOfRawData & lFileAlignMask))
    {
      //出現非法節
      delete lpDynPEBuff;
      return false;
    }

    //加載改節
    memcpy(lpDynPEBuff + pISH->VirtualAddress, lpStaticPEBuff + pISH->PointerToRawData, pISH->SizeOfRawData);
  }

  //修改導入表,導入程序執行過程中要用到的API函數地址
  if(pINH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size > 0) //大於0說明有導入表
  {
    IMAGE_IMPORT_DESCRIPTOR *pIID = (IMAGE_IMPORT_DESCRIPTOR *)(lpDynPEBuff + /
      pINH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);

    //循環掃描每個將有函數導入的dll
    for(; pIID->Name != NULL; pIID++)
    {
      /*曾看過OllyDump源代碼,那裏在重建導入表的時候,並沒有初始化OriginalFirstThunk這個字段,
      所以這裏也不對OriginalFirstThunk這個字段進行處理了*/
      IMAGE_THUNK_DATA *pITD = (IMAGE_THUNK_DATA *)(lpDynPEBuff + pIID->FirstThunk);

      HINSTANCE hInstance = LoadLibrary(lpDynPEBuff + pIID->Name);
      if(hInstance == NULL)
      {
        //導入這個dll失敗
        delete lpDynPEBuff;
        return false;
      }

      //循環掃描dll內每個被導入函數
      for(; pITD->u1.Ordinal != 0; pITD++)
      {
        FARPROC fpFun;
        if(pITD->u1.Ordinal & IMAGE_ORDINAL_FLAG32)
        {
          //函數是以序號的方式導入的
          fpFun = GetProcAddress(hInstance, (LPCSTR)(pITD->u1.Ordinal & 0x0000ffff));
        }
        else
        {
          //函數是以名稱方式導入的
          IMAGE_IMPORT_BY_NAME * pIIBN = (IMAGE_IMPORT_BY_NAME *)(lpDynPEBuff + pITD->u1.Ordinal);
          fpFun = GetProcAddress(hInstance, (LPCSTR)pIIBN->Name);
        }

        if(fpFun == NULL)
        {
          //導出這個函數失敗
          delete lpDynPEBuff;
          return false;
        }

        pITD->u1.Ordinal = (long)fpFun;
      }

      FreeLibrary(hInstance);
    }
  }


  //重定位處理
  if(pINH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size > 0)
  {
    //取第一個重定位塊
    IMAGE_BASE_RELOCATION *pIBR = (IMAGE_BASE_RELOCATION *)(lpDynPEBuff + /
      pINH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);

    long lDifference = (long)lpDynPEBuff - pINH->OptionalHeader.ImageBase;

    //循環每個重定位塊
    for(; pIBR->VirtualAddress != 0; )
    {
      char *lpMemPage = lpDynPEBuff + pIBR->VirtualAddress;
      long lCount = (pIBR->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) >> 1;

      //對這個頁面中的每個需重定位的項進行處理
      short int *pRelocationItem = (short int *)((char *)pIBR + sizeof(IMAGE_BASE_RELOCATION));
      for(int nIndex = 0; nIndex < lCount; nIndex++)
      {
        int nOffset = pRelocationItem[nIndex] &0x0fff;
        int nType = pRelocationItem[nIndex] >> 12;

        //雖然windows定義了很多重定位類型,但是在PE文件中只能見到0和3兩種
        if(nType == 3)
        {
          *(long *)(lpDynPEBuff + nOffset) += lDifference;
        }
        else if(nType == 0)
        {
          //什麼也不做
        }
      }

      //pIBR指向下一個重定位塊
      pIBR = (IMAGE_BASE_RELOCATION *)(pRelocationItem + lCount);
    }

  }

  delete lpDynPEBuff;

  return true;
}
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章