// 增加区段.cpp : Defines the entry point for the console application.
//


#include <windows.h>
#include <stdio.h>
#include <winbase.h>


bool OpenMyFile(char fileName[]);
LPVOID AddSection(LPVOID ImageBase,char sectionName[],DWORD SectionNumber);
DWORD ToAlign(DWORD SectionNumber,DWORD AlignSize); //取整 第二个参数表示以多少进行取整

DWORD addNumber;  //新区段的字节数
DWORD VAValue;    //保存原入口VA值
char chao[MAX_PATH]="MessageBoxA GetProAddress LoadLibraryA user32.dll kernel32.dll";
DWORD addRess;    //保存GETMODULEHANDL地址

int main(int argc, char* argv[])
{
  addRess  =(DWORD)GetProcAddress(GetModuleHandle("kernel32.dll"),"GetModuleHandleA");

  addNumber = 100;

  char fileName[] = "text.exe";   //欲测试的程序
  

  if(!OpenMyFile(fileName))
    printf("failed!!!\n");


  return 0;
}


bool OpenMyFile(char fileName[])
{

  HANDLE hFile;
  hFile = CreateFile(fileName,      //打开文件
          GENERIC_READ|GENERIC_WRITE,
          FILE_SHARE_READ|FILE_SHARE_WRITE,
          NULL,OPEN_EXISTING,
          FILE_ATTRIBUTE_NORMAL,
          NULL);
  if(!hFile)
    return false;
  
  DWORD fileSize = GetFileSize(hFile,NULL); //得到文件大小

  HANDLE hMap;
  hMap = CreateFileMapping(hFile,NULL,   
              PAGE_READWRITE,0,
              fileSize+0x2000,0);
  
  if(!hMap)
    return false;

  LPVOID ImageBase;
  ImageBase = MapViewOfFile(hMap,
              FILE_MAP_ALL_ACCESS,
              0,0,0);

  if(!ImageBase)
    return false;

  //判断是否为有效的PE文件
  PIMAGE_DOS_HEADER pDos;
  pDos = (PIMAGE_DOS_HEADER)ImageBase;
  if('ZM'!=pDos->e_magic)
    return false;

  PIMAGE_NT_HEADERS pNt;
  pNt = (PIMAGE_NT_HEADERS)((DWORD)ImageBase+pDos->e_lfanew);
  if('EP' !=pNt->Signature)
    return false;
  
  LPVOID newSectionName;   //指向新区段节名
  newSectionName = AddSection(ImageBase,".fan",addNumber);
  DWORD len = strlen(chao);   //把新区段要用到的字符COYP到其中
 _asm
 {
    mov esi,pNt
    mov ebx,dword ptr[esi+28h]   //入口RVA值 
    add ebx,dword ptr[esi+34h]   //与映像值相加
    mov VAValue,ebx
    mov eax,newSectionName
    push dword ptr[eax+0ch]     //得到新区段虚拟RVA
    pop dword ptr[esi+28h]       //修改到新入口
    mov ecx,dword ptr[esi+28h]   //把入口值加上字符串长度
    add ecx,len           //加上字符长度
    inc ecx
    add ecx,4           //加上原入口RVA值  
    add ecx,4           //加上GETMODULHAND地址的四个字节
    mov dword ptr[esi+28h],ecx
    lea esi,chao
    mov edi,dword ptr[eax+14h]
    add edi,ImageBase
    mov ecx,len
    inc ecx
    cld
    rep movs byte ptr[edi],byte ptr[esi]
    
    lea esi,addRess         //写入GETMODULEHANDLE的地址
    mov ecx,4
    cld
    rep movs byte ptr[edi],byte ptr[esi]

    lea esi,VAValue         //把原入口RVA值写到字符串后
    mov ecx,4
    cld
    rep movs byte ptr[edi],byte ptr[esi]
    
    lea esi,fan           //完成进入前原入口前的一些任务 如写病毒代码
    mov ecx,30h
    cld
    rep movs byte ptr[edi],byte ptr[esi]
    
 }

  UnmapViewOfFile(ImageBase);
  CloseHandle(hMap);
  CloseHandle(hFile);

  return true;
fan:
  //在此处填写要在程序执行前想执行的代码
 _asm
 {  
      call zhi   //占五个字节
zhi:  pop ebx    
    sub ebx,5  //此时EBX指向 CALL ZHI这条指令
    sub ebx,4  //此时EBX指向存放原入口的RVA值
    push ebx  
  
    push ebp
    mov ebp,esp
    sub esp,10h //存放要用到的数据
  
    sub ebx,4
    mov esi,ebx
    sub ebx,0Dh
    push ebx       //此时EBX指向KERNEL32 DLL字符串
    call dword ptr[esi]  //得到KERNEL32基址
      
    add esp,10h       //堆栈平衡  
    pop ebp 
    pop ebx
    jmp dword ptr[ebx]    //跳回到原程序入口
          
 }



}


LPVOID AddSection(LPVOID ImageBase,char sectionName[],DWORD SectionNumber)
{
    PIMAGE_NT_HEADERS pNt;
    DWORD fileAlign;   //文件对齐大小
    DWORD meryAlign;   //内存对齐大小
    LPVOID oldSection; //指向最后一个区段
    LPVOID newSection; //指向新的区段节表
    
  _asm
  {
    mov esi,ImageBase
    add esi,dword ptr[esi+3ch]
    mov pNt,esi  
    mov cx,word ptr[esi+6]
    movzx ecx,cx
    inc word ptr[esi+6]   //增加区段数目加一
    push dword ptr[esi+3ch]
    pop  fileAlign
    push dword ptr[esi+38h]
    pop meryAlign
    add esi,0F8h       //让ESI指向节表首地址
    mov eax,28h
    mov ebx,ecx
    imul ebx
    add esi,eax      //让ESI指向节表尾地址前
    mov newSection,esi
    sub esi,28h
    mov oldSection,esi
    
  }

   //以下是为新区段给名称
    int i=0;  
      char *newS =(char*)newSection;

    while(sectionName[i]!='\0')
     {    
      *newS=sectionName[i];
      ++newS;  
      ++i;
     }


    //增加新区段其它信息
 _asm
 {  
      mov esi,newSection
    push 0E00000E0h
    pop dword ptr[esi+24h]
    push SectionNumber    //新区段的内存大小
    pop dword ptr[esi+8h]
    
 }
    
  DWORD newFileSize =ToAlign(SectionNumber,fileAlign);  //新区段大小文件取整得到其文件大小
    _asm mov esi,newSection
  _asm mov eax,newFileSize
  _asm mov dword ptr[esi+10h],eax  //将新区段文件大小写到区段信息中

  //接下来就是写新区段的文件偏移和内存RVA值 这个值是根据原最后一个区段的信息算出的
_asm
{
    mov esi,oldSection
    mov ebx,dword ptr[esi+08h]    //虚拟大小
  add ebx,dword ptr[esi+0ch]  //虚拟偏移
    mov ecx,dword ptr[esi+10h]  //文件大小
  add ecx,dword ptr[esi+14h]  //文件偏移
  push fileAlign        //文件取整
  push ecx
  call ToAlign
  add esp,8
  mov esi,newSection
  mov dword ptr[esi+14h],eax 
  push meryAlign
  push ebx
  call ToAlign
  add esp,8
  mov dword ptr[esi+0ch],eax
//新区段RVA值加虚拟大小进行取整得新映像大小
  add eax,dword ptr[esi+08h]
  push meryAlign
  push eax
  call ToAlign
  add esp,8
  mov ebx,pNt
  mov dword ptr[ebx+50h],eax //修正映像大小
//新区段前SectionNumber个字节清零
  push dword ptr[esi+14h]
  pop edi
  add edi,ImageBase
  mov ecx,SectionNumber     //把新区段数据SectionNumber个字节置零
  xor eax,eax
  cld
  rep stos byte ptr[edi]
  mov eax,esi
  
}
       
}

//区段取整
DWORD ToAlign(DWORD SectionNumber,DWORD AlignSize)
{

  DWORD size = SectionNumber%AlignSize;      //取余
  DWORD size2 = SectionNumber/AlignSize;   //取整
  if(size == 0)  //如果余数为0,则证明已是其整数倍
    return SectionNumber;
  else
      return (++size2)*AlignSize;
 
}

刚学,代码有点不整,大家见谅

上传的附件 增加区段.rar