最经刚刚看完PE 文件的格式规范,发现手工添加区块太麻烦,所以 自己花了4个小时编写一个自动添加区段的程序。(高手就不要看了,鄙人就不献丑了)


添加区段一共分四个步骤
  1 修改块的数目(即文件头的NumberOfSections字段)
  2 增加块头  

 3 修改PE文件的景象尺寸(即可选头的SizeOfImage字段) 
 4 增加块 

代码注释很详细,本人就不废话了。

定义的变量如下:
private:

  IMAGE_DOS_HEADER      dos_header;      //大小是64
  IMAGE_NT_HEADERS32    nt_header;       //大小是248
  IMAGE_SECTION_HEADER  *section_header; //大小是40
 函数如下。

BOOL CPeFile::ReadPEFile(HANDLE hFile)
{
  DWORD dwRead;

   if(hFile==INVALID_HANDLE_VALUE)
     return FALSE;

    //读取DOS  MZ header
    if(! ReadFile(hFile,(LPBYTE)&dos_header,sizeof(IMAGE_DOS_HEADER),&dwRead,NULL))
    return FALSE;
  //判断读取是否成功
  if(dwRead!=sizeof(IMAGE_DOS_HEADER))
    return FALSE;   

   //判断是否是DOS MZ header
    if(dos_header.e_magic!=0x5A4D)  
    return FALSE;

  //将文件指针移到真正的PE文件头
   SetFilePointer(hFile,dos_header.e_lfanew,NULL,FILE_BEGIN);
   
  //读取PE文件头
    if(! ReadFile(hFile,(LPBYTE)&nt_header,sizeof(IMAGE_NT_HEADERS32),&dwRead,NULL))
    return FALSE;
  //判断读取是否成功
  if(dwRead!=sizeof(IMAGE_NT_HEADERS32))
    return FALSE;

  //判断是否是真正的PE文件
    if(nt_header.Signature!=0x4550) 
    return FALSE;
  

    WORD numSect=nt_header.FileHeader.NumberOfSections;
    section_header=new IMAGE_SECTION_HEADER[numSect];
    if(section_header==NULL)  //申请内存失败   
     return FALSE;
 
     //读取块表
    if(! ReadFile(hFile,(LPBYTE)section_header,numSect*sizeof(IMAGE_SECTION_HEADER),&dwRead,NULL))
    return FALSE;
  //判断读取是否成功
  if(dwRead!=numSect*sizeof(IMAGE_SECTION_HEADER))
    return FALSE;
    return TRUE;
}


BOOL CPeFile::AddSection(BYTE name[IMAGE_SIZEOF_SHORT_NAME],DWORD len,HANDLE hFile)
{
  

  if(hFile==INVALID_HANDLE_VALUE)     
     return FALSE;    
   
   IMAGE_SECTION_HEADER   newSect;  //新块
   
   //获取信息
   DWORD fileAlign=nt_header.OptionalHeader.FileAlignment;     //文件粒度
   DWORD sectAlign=nt_header.OptionalHeader.SectionAlignment;  //块的粒度   
   WORD  numofsect=nt_header.FileHeader.NumberOfSections;      //块的数目

/*****************************初始化newSect的数据************************/
    //重定位偏移
    newSect.PointerToRelocations=0;
  //重定位表数目
  newSect.NumberOfRelocations=0;
  //行号表的偏移
  newSect.PointerToLinenumbers=0;
  //行号表的中行号数目
  newSect.NumberOfLinenumbers=0;
    //块属性
  newSect.Characteristics=IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
    //块的名字
    for(int i=0;i<IMAGE_SIZEOF_SHORT_NAME;i++)
       newSect.Name[i]=name[i];
  //快的真实长度
  newSect.Misc.PhysicalAddress=len;
     //文件中对齐后的尺寸
  newSect.SizeOfRawData=(len%fileAlign?fileAlign*(len/fileAlign+1):len);
  //在文件中的偏移
    newSect.PointerToRawData=section_header[numofsect-1].PointerToRawData+section_header[numofsect-1].SizeOfRawData;        
    
  //该块的RVA  
  DWORD virtualSize;  
  if(section_header[numofsect-1].SizeOfRawData % sectAlign)  //计算上一块的景象大小    
    virtualSize=sectAlign*(section_header[numofsect-1].SizeOfRawData/sectAlign+1);
  else    
    virtualSize=section_header[numofsect-1].SizeOfRawData;
    newSect.VirtualAddress=section_header[numofsect-1].VirtualAddress+virtualSize;        

/**********************************修改PE文件**************************************/    
    DWORD dwWrite;
  DWORD pointloc;

  //修改快的数目
  WORD newNumofsect=1+numofsect;
  //将文件指针移到块数目位置
    SetFilePointer(hFile,dos_header.e_lfanew+6,NULL,FILE_BEGIN);
    if(! WriteFile(hFile,(LPBYTE)&newNumofsect,sizeof(WORD),&dwWrite,NULL))
    return FALSE;
  //判断是否写入成功
  if(dwWrite!=sizeof(WORD))
    return FALSE;

     //修改PE文件的景象尺寸
  DWORD size=nt_header.OptionalHeader.SizeOfImage+(len%sectAlign?sectAlign*(len/sectAlign+1):len);;
  //将文件指针移到块数目位置
    SetFilePointer(hFile,dos_header.e_lfanew+0x50,NULL,FILE_BEGIN);
    if(! WriteFile(hFile,(LPBYTE)&size,sizeof(DWORD),&dwWrite,NULL))
    return FALSE;
  //判断是否写入成功
  if(dwWrite!=sizeof(DWORD))
    return FALSE;

  //增加块头
     pointloc=dos_header.e_lfanew+sizeof(IMAGE_NT_HEADERS32)+sizeof(IMAGE_SECTION_HEADER)*nt_header.FileHeader.NumberOfSections;
  //将文件指针移到所有的块末尾。
    SetFilePointer(hFile,pointloc,NULL,FILE_BEGIN);    
    if(!WriteFile(hFile,(LPBYTE)&newSect,sizeof(IMAGE_SECTION_HEADER),&dwWrite,NULL))
    return FALSE;
  //判断是否写入成功
  if(dwWrite!=sizeof(IMAGE_SECTION_HEADER))
    return FALSE;
  

    //增加块     
   char ret[200]={'0'};
    //将文件指针移到所有的块末尾。
    SetFilePointer(hFile,newSect.PointerToRawData,NULL,FILE_BEGIN);    
    if(!WriteFile(hFile,(LPBYTE)ret,newSect.SizeOfRawData,&dwWrite,NULL))
    return FALSE;
  //判断是否写入成功
  if(dwWrite!=newSect.SizeOfRawData)
    return FALSE;
     
  return TRUE;
  
}

代码还不是很完善,望谅解。比如:没有判断所有块头之后是否可以添加新块头,
还有就是没有判断所有块之后是否还有其他信息,比如COFF行号 COFF符号表,Code View调试信息 。

上传的附件 LoadPE.rar