24小时热门版块排行榜    

查看: 286  |  回复: 0
当前主题已经存档。

sdlj8051

金虫 (著名写手)

[交流] 一段仿真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;
}

[ Last edited by 幻影无痕 on 2006-11-11 at 07:31 ]
回复此楼

» 猜你喜欢

已阅   回复此楼   关注TA 给TA发消息 送TA红花 TA的回帖
相关版块跳转 我要订阅楼主 sdlj8051 的主题更新
普通表情 高级回复 (可上传附件)
最具人气热帖推荐 [查看全部] 作者 回/看 最后发表
[考研] 274求调剂 +3 cgyzqwn 2026-03-01 6/300 2026-03-01 21:24 by cgyzqwn
[考研] 299求调剂 +3 Y墨明棋妙Y 2026-02-28 5/250 2026-03-01 21:01 by tangxiaotian
[考研] 材料化工调剂 +10 今夏不夏 2026-03-01 11/550 2026-03-01 19:49 by 无懈可击111
[考研] 高分子化学与物理调剂 +6 好好好1233 2026-02-28 12/600 2026-03-01 19:48 by 好好好1233
[考研] 化工299分求调剂 一志愿985落榜 +5 嘻嘻(*^ω^*) 2026-03-01 5/250 2026-03-01 19:47 by 无际的草原
[考研] 265分求调剂不调专业和学校有行学上就 +5 礼堂丁真258 2026-02-28 7/350 2026-03-01 19:12 by Js512888
[考研] 291分工科求调剂 +9 science饿饿 2026-03-01 10/500 2026-03-01 18:55 by 18137688336
[考研] 0857调剂 +3 一ll半 2026-02-28 3/150 2026-03-01 18:32 by 热情沙漠
[考研] 321求调剂一志愿东北林业大学材料与化工英二数二 +4 虫虫虫虫虫7 2026-03-01 7/350 2026-03-01 16:52 by caszguilin
[考研] 0856材料求调剂 +4 麻辣鱿鱼 2026-02-28 4/200 2026-03-01 16:51 by caszguilin
[考研] 化工专硕342,一志愿大连理工大学,求调剂 +3 kyf化工 2026-02-28 4/200 2026-03-01 16:49 by yywzz
[基金申请] 刚录用,没有期刊号,但是在线可看的论文可以放为代表作吗 10+3 arang1 2026-03-01 3/150 2026-03-01 16:43 by babero
[考研] 307求调剂 +5 wyyyqx 2026-03-01 5/250 2026-03-01 15:21 by Fff-1
[考研] 课题组接收材料类调剂研究生 +3 gaoxiaoniuma 2026-02-28 4/200 2026-03-01 14:30 by jjj三跨
[考研] 寻找调剂 +4 LYidhsjabdj 2026-02-28 4/200 2026-03-01 10:56 by sunny81
[论文投稿] 求助coordination chemistry reviews 的写作模板 10+3 ljplijiapeng 2026-02-27 4/200 2026-03-01 09:07 by babero
[基金申请] 面上模板改不了页边距吧? +5 ieewxg 2026-02-25 6/300 2026-03-01 00:10 by addressing
[考研] 304求调剂 +3 52hz~~ 2026-02-28 5/250 2026-03-01 00:00 by 52hz~~
[考研] 292求调剂 +3 yhk_819 2026-02-28 3/150 2026-02-28 21:57 by gaoxiaoniuma
[硕博家园] 【博士招生】太原理工大学2026化工博士 +4 N1ce_try 2026-02-24 8/400 2026-02-26 08:40 by N1ce_try
信息提示
请填处理意见