pe_c++

 /**//**************************************************************************
*    文件名:        Main.cpp
*    日  期:        2009年1月13日
*    作  者:        rawdata
*    描  述:        增加3个节
       空间都用new,所以新生成的PE文件在新的内存区域
***************************************************************************/

#include <windows.h>
#include <windowsx.h>
#include <winnt.h>
#include <iostream>
using namespace std;

#pragma warning(disable:4312)
#pragma warning(disable:4311)
#pragma warning(disable:4244)

int main(int argc,char**argv)
{
    //------------------- 主要缓冲区定义 ----------------------
   
    BYTE* pDos = NULL;        //Dos头和Stub区
    DWORD dwSizeDos = 0;    //Dos头 大小
    DWORD dwSizeStub = 0;    //Dos Stub区大小

    BYTE* pNT = NULL;        //NT头
    DWORD dwSizeNT = 0;        //该区大小

    BYTE* pSecH = NULL;        //节表
    DWORD dwSizeSecH = 0;    //该区大小
    WORD dwSizeAdd = 3;        //增加的节的个数

    BYTE* pDelta = NULL;    //文件对齐填充数据
    DWORD dwSizeDelta = 0;    //该区大小

    BYTE* pPrevSec = NULL;    //节块
    DWORD dwSizePrevSec = 0;//该区大小

    BYTE* pAddSec = NULL;    //新增的节块
    DWORD dwSizeAddSec = 0;    //该区大小

    //---------------------- 其他临时定义 --------------------
   
    const char* pszFilePath = NULL;            //文件路径
    HANDLE hFile = NULL;                    //文件句柄

    PIMAGE_DOS_HEADER        pIDH = NULL;    //Dos头
    PIMAGE_NT_HEADERS        pINH = NULL;    //NT 头
    PIMAGE_SECTION_HEADER*    ppISH = NULL;    //节表

    DWORD dwRealRead = 0;                    //实际每次文件读取的字节数
    DWORD dwMiniPointer = 0;                //第一个section的位置
    BOOL bNeedModify = FALSE;                //是否有必要需要修改节块的文件指针

    DWORD dwRawDataSize = 10*1024;                //增加区段的数据大小

    DWORD dwTmp=0,dwTmp2=0,dwTmp3 = 0;
   
    //Dos 头
    //===============================================================================
    //打开文件、读取Dos头
 //===========================================================================
 //
 //typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header "MZ"
     //WORD   e_magic;                // Magic number
     //WORD   e_cblp;                 // Bytes on last page of file
     //WORD   e_cp;                   // Pages in file
     //WORD   e_crlc;                 // Relocations
     //WORD   e_cparhdr;              // Size of header in
                                   // paragraphs
     //WORD   e_minalloc;             // Minimum extra paragraphs
                                   // needed
     //WORD   e_maxalloc;             // Maximum extra paragraphs
                                   // needed
     //WORD   e_ss;                   // Initial (relative) SS
                                   // value
     //WORD   e_sp;                   // Initial SP value
     //WORD   e_csum;                 // Checksum
     //WORD   e_ip;                   // Initial IP value
     //WORD   e_cs;                   // Initial (relative) CS
                                   // value
     //WORD   e_lfarlc;               // File address of relocation
                                   // table
     //WORD   e_ovno;                 // Overlay number
     //WORD   e_res[4];               // Reserved words
     //WORD   e_oemid;                // OEM identifier
                                   // (for e_oeminfo)
     //WORD   e_oeminfo;              // OEM information;
                                   // e_oemid specific
     //WORD   e_res2[10];             // Reserved words
     //LONG   e_lfanew;               // File address of the new
                                   // exe header
   //} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
 //===============================================================================
 
    pszFilePath = argv[0];
    pszFilePath = "BeingInjued.exe";//Test

    cout<<"PE FileName:"<<pszFilePath<<endl;

    if(0 == lstrcmp(pszFilePath,""))
    {
        cout<<"文件路径不能为空!"<<endl;
        return -1;
    }

    hFile = CreateFile(pszFilePath,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,NULL);

    if(INVALID_HANDLE_VALUE == hFile)
    {
        cout<<"打开文件失败!"<<endl;
        hFile = NULL;
        goto Error;
    }

    dwSizeDos = sizeof(IMAGE_DOS_HEADER);//dos头大小
    pDos = new BYTE[dwSizeDos];  //Dos头和Stub区
    memset(pDos,0,dwSizeDos);  //initiate

    if(!ReadFile(hFile,pDos,dwSizeDos,&dwRealRead,NULL))
    {
        cout<<"读取Dos头失败!"<<endl;
        goto Error;
    }
    cout<<"Dos Header: "<<dwRealRead<<"bytes have read."<<endl;

    //获得IMAGE_DOS_HEADER指针,效验
    pIDH = (PIMAGE_DOS_HEADER)pDos;  //dos_header pointer: pIDH和pDos区别:一个是结构体指针,指向新开辟的结构;一个是字符指针,指向未知的内存空间
          //两个指针指向同一区域20090924
    if(memcmp(&(pIDH->e_magic),"MZ",2)!=0) //check dos header validate
    {
        cout<<"不是有效的PE文件格式!"<<endl;
        goto Error;
    }

    //DOS Stub
    //================================================================================
   
    dwSizeStub = pIDH->e_lfanew - dwSizeDos;
    pDos = (BYTE*)realloc(pDos,dwSizeDos + dwSizeStub);  //原先pDos指针指向的DOS头变成(DOS头+STUB)
    memset(pDos+dwSizeDos,0,dwSizeStub);   //initiate 0 of (dos+stub)
   
    if(!ReadFile(hFile,pDos+dwSizeDos,dwSizeStub,&dwRealRead,NULL))
    {
        cout<<"读取DosStub失败!"<<endl;
        goto Error;
    }
    cout<<"Dos Stub: "<<dwRealRead<<"bytes have read."<<endl;

    //NT Header
    //================================================================================
   
   

    dwSizeNT = sizeof(IMAGE_NT_HEADERS); //nt header size
    pNT = new BYTE[dwSizeNT];                  //nt pointer
    memset(pNT,0,dwSizeNT);
   
    if(!ReadFile(hFile,pNT,dwSizeNT,&dwRealRead,NULL))
    {
        cout<<"读取NT Headers失败!"<<endl;
        goto Error;
    }
   
    //获得NT指针
    pINH = (PIMAGE_NT_HEADERS)pNT;
    if(memcmp(&(pINH->Signature),"PE",2)!=0)
    {
        cout<<"错误的PE文件格式!"<<endl;
        goto Error;
    }
 //up is the judgement of pe file
 //============================================================================ 
    //节表
    //================================================================================
   
    dwSizeSecH = (pINH->FileHeader.NumberOfSections + dwSizeAdd) * sizeof(IMAGE_SECTION_HEADER); //每个节大小固定,原先节的个数+新增加的节个数       
    pSecH = new BYTE[dwSizeSecH]; //指向节表的字符指针
    memset(pSecH,0,pINH->FileHeader.NumberOfSections + dwSizeAdd);

    ppISH = (PIMAGE_SECTION_HEADER*)new DWORD[pINH->FileHeader.NumberOfSections + dwSizeAdd]; //指向节表的结构指针数组
    memset(ppISH,0,sizeof(DWORD)*(pINH->FileHeader.NumberOfSections + dwSizeAdd));

    for(UINT i=0;i<pINH->FileHeader.NumberOfSections;i++) //读取原先旧的节内容
    {
        if(!ReadFile(hFile,pSecH+i*sizeof(IMAGE_SECTION_HEADER),
            sizeof(IMAGE_SECTION_HEADER),&dwRealRead,NULL))
        {
            cout<<"读取Section Headers失败!"<<endl;
            goto Error;
        }
       
        ppISH[i] = (PIMAGE_SECTION_HEADER)(pSecH+i*sizeof(IMAGE_SECTION_HEADER));
        //ppISH[0]=pSecH
        //ppISH[1]=pSecH+sizeof(IMAGE_SECTION_HEADER)
        //ppISH[2]=pSecH+2*sizeof(IMAGE_SECTION_HEADER)
        //ppISH[3]=pSecH+3*sizeof(IMAGE_SECTION_HEADER)
        //发现程序中用到的指针都是指向头部,比如节表,ppISH, pSecH都是指向节表头部,不移动,
        //读取内容时只是根据偏移地址来读取,这样的好处是下次用到这个指针的时候课可以很方便的找到:)
        cout<<"Name: "<<ppISH[i]->Name<<endl;
        cout<<"Size: "<<ppISH[i]->SizeOfRawData<<endl;
        cout<<"Virtual Adress: "<<ppISH[i]->VirtualAddress<<endl;
        cout<<"PointerToRawData: "<<ppISH[i]->PointerToRawData<<endl;
    }
    cout<<endl;


    //节块
    //================================================================================

    pPrevSec = (BYTE*)malloc(0);
    for(i=0;i<pINH->FileHeader.NumberOfSections;i++)
    {
        dwTmp = ppISH[i]->SizeOfRawData; //磁盘上,节根据FileAlignment对齐后的大小,必须是FileAlignment的倍数
        //节的物理大小
        pPrevSec = (BYTE*)realloc(pPrevSec,dwTmp2 + dwTmp); //指向内存中未知地方的一个节大小的指针
        memset(pPrevSec+dwTmp2,0,dwTmp);
       
        SetFilePointer(hFile,ppISH[i]->PointerToRawData,NULL,FILE_BEGIN); //pointerToRawData:从文件开头到对应节的偏移量
 //hFile目前指向第一个节
        cout<<i<<":PointerToRawData:"<<ppISH[i]->PointerToRawData<<endl;
        cout<<"BlockSize:"<<ppISH[i]->SizeOfRawData<<endl;
        cout<<"Virtual Address:"<<ppISH[i]->VirtualAddress<<endl;  //当PE文件读入内存后,对应节的RVA

        if(!ReadFile(hFile,pPrevSec+dwTmp2,dwTmp,&dwRealRead,NULL)){
            cout<<"ReadFile Faield!"<<endl;
            goto Error;
        }

        dwTmp2 += dwTmp;
    }
    dwSizePrevSec = dwTmp2; //原先节的总大小,此时hFile指向第一个节块的头部


    //数据填补、修改部分
    //================================================================================

    //第一个节块的位置
    for(i=0;i<pINH->FileHeader.NumberOfSections;i++)
    {
        if(ppISH[i])
        {
            if(0 == dwMiniPointer)
                dwMiniPointer = (DWORD)ppISH[i]->PointerToRawData; //pointerToRawData:从文件开头到对应节的偏移量
           
            if((ppISH[i]->PointerToRawData)<dwMiniPointer)
                dwMiniPointer = (DWORD)ppISH[i]->PointerToRawData;
        }
    }
    cout<<"Prev First Section Pos:"<<dwMiniPointer<<endl;
 //ppISH[0]->PointerToRawData不应该是第一个结块的位置么???
 //这里是最小的结块是第一个结块,难道说ppISH[0]--[n]不是按从小到大的顺序排的?
 
 
    //空白填充区大小    ,先计算好
    dwTmp = (dwSizeDos+dwSizeStub+dwSizeNT+dwSizeSecH); //前面头部总大小
    if(dwMiniPointer >= dwTmp) //第一个结块在 前面那些头部的后面
        dwSizeDelta = dwMiniPointer - dwTmp; //dosheader,ntheader,sectionheader,section之间有空白间隙
    else   //第一个结块在 前面那些头部的前面??可能么。。。
        //说明pe文件只是按照pe文件那个结构,但是不是顺序的,可能节块在前面,而且最前面的结块不一定是第一个结块。
        //它在内存中是东一块西一块的,不是一个整体。
    {
        dwSizeDelta = dwTmp % (pINH->OptionalHeader.FileAlignment); //文件对其粒度取余
       
        if(dwSizeDelta != 0) //前面那些头部总大小和文件对其粒度不对其
            dwSizeDelta = pINH->OptionalHeader.FileAlignment - dwSizeDelta; //对其粒度-总大小得到空白区域,包括dosheader--ntheader
                     //ntheader--sectionheader
                     //sectionheader
        else dwSizeDelta = 0;

        bNeedModify = TRUE;
    }
    cout<<"Delta:"<<dwSizeDelta<<endl;
    pDelta = new BYTE[dwSizeDelta]; //空白区间
    memset(pDelta,0,dwSizeDelta);

    dwMiniPointer = dwTmp;
    dwMiniPointer += dwSizeDelta; //前面头部总大小+空白区间=前面头部符合文件对其粒度的总大小,即内存中从dosheader---sectionheader最末端(包括空白)

    //修改 NT 头,必须修改
    pINH->FileHeader.NumberOfSections += dwSizeAdd;

   
    //修改原来节表头的文件指针
    cout<<endl;
    if(bNeedModify) //节块可能在那些头部的前面
    {
        for(i=0;i<(UINT)(pINH->FileHeader.NumberOfSections - dwSizeAdd);i++) //还是在原先那些结块循环
        {
            if(0 != i)
                ppISH[i]->PointerToRawData =
                ppISH[i-1]->PointerToRawData +
                ppISH[i-1]->SizeOfRawData;
            else
               ppISH[i]->PointerToRawData = dwMiniPointer; pointerToRawData:从文件开头到对应节的偏移量
            cout<<"New Entry:"<<i<<": "<<ppISH[i]->PointerToRawData<<endl;
        }
    }
 //使第一个结块在内存中在最前面,排序啦

    //填充增加的节表头
    cout<<endl;
    char szName[8] = ".";
    char szNum[7] = {0};
    szName[5] = 0;
    dwTmp = ppISH[0]->VirtualAddress; //第一个节表虚拟地址
    dwTmp2 = pINH->OptionalHeader.SectionAlignment; //节粒度
    dwTmp3 = pINH->OptionalHeader.FileAlignment; //文件粒度
    int nCount = 1;
    DWORD dwNewAllocSize = 0;

    for(i=(pINH->FileHeader.NumberOfSections - dwSizeAdd);
        i<pINH->FileHeader.NumberOfSections;i++) //新增加的那些节填充数据
    {                                                  
        ppISH[i] = (PIMAGE_SECTION_HEADER)(pSecH+i*sizeof(IMAGE_SECTION_HEADER)); //先创建节表
        memset(ppISH[i],0,sizeof(IMAGE_SECTION_HEADER));
       
        ppISH[i]->Characteristics = ppISH[0]->Characteristics;
       
        sprintf(szNum,"%d",nCount);
        memcpy(szName+1,szNum,7);
        memcpy(ppISH[i]->Name,szName,8); //取节名

        dwNewAllocSize = dwRawDataSize % dwTmp3; //文件尾添加10*1024空白数据,但是要对其
        if(dwNewAllocSize != 0) //不对其
           dwNewAllocSize = dwRawDataSize + (dwTmp3 - dwNewAllocSize); //文件不对其,多了dwNewAllocSize,所以dwRawDataSize- dwNewAllocSize
                   //但是多退少补,所以多加一个文件粒度
        else dwNewAllocSize = dwRawDataSize;
        ppISH[i]->SizeOfRawData = dwNewAllocSize;  //第i个节的大小

        //增加的文件区段
        dwSizeAddSec += ppISH[i]->SizeOfRawData;
       
        dwNewAllocSize = dwRawDataSize % dwTmp2; //还要节对其
        if(dwNewAllocSize != 0)
           dwNewAllocSize = dwRawDataSize + (dwTmp2 - dwNewAllocSize);
        else dwNewAllocSize = dwRawDataSize;

        ppISH[i]->Misc.VirtualSize = dwNewAllocSize;

        //修改NT头,必须修改
        pINH->OptionalHeader.SizeOfImage += dwNewAllocSize;

        ppISH[i]->PointerToRawData = (ppISH[i-1]->PointerToRawData+ppISH[i-1]->SizeOfRawData);        

        ppISH[i]->VirtualAddress = ppISH[i]->PointerToRawData;
        if(ppISH[i]->VirtualAddress>=(0x7FFFFFFF-dwNewAllocSize))
        {
            cout<<"Error!Virtual address overflow!"<<endl;
            goto Error;
        }
        cout<<"New Entry:"<<i<<": "<<ppISH[i]->PointerToRawData<<endl;
        nCount++;
    }

    //修改NT头,可选,不设置也能正常运行,但是为保证数据准确,还是写上
    pINH->OptionalHeader.SizeOfHeaders = dwMiniPointer;

 

    //新的Sections,必须满足文件对齐
    pAddSec = new BYTE[dwSizeAddSec];
    memset(pAddSec,0,dwSizeAddSec);

    //重建文件: dumpOK.exe
    //================================================================================

    CloseHandle(hFile);
    hFile = CreateFile("dumpOK.exe",GENERIC_READ|GENERIC_WRITE,NULL,NULL,CREATE_ALWAYS,
        FILE_ATTRIBUTE_NORMAL,NULL);
   
    //Dos Data
    if(!WriteFile(hFile,pDos,dwSizeDos+dwSizeStub,&dwRealRead,NULL))
    {
        cout<<"WriteFile Faield!"<<endl;
        goto Error;
    }
    cout<<"Dos Data:"<<dwRealRead<<" bytes write."<<endl;


    //NT 头
    if(!WriteFile(hFile,pNT,dwSizeNT,&dwRealRead,NULL))
    {
        cout<<"WriteFile Faield!"<<endl;
        goto Error;
    }
    cout<<"NT Data:"<<dwRealRead<<" bytes write."<<endl;

    //节表  (包括新加的)
    if(!WriteFile(hFile,pSecH,dwSizeSecH,&dwRealRead,NULL))
    {
        cout<<"WriteFile Faield!"<<endl;
        goto Error;
    }
    cout<<"Section Headers:"<<dwRealRead<<" bytes write."<<endl;

    //填充空白数据
    if(!WriteFile(hFile,pDelta,dwSizeDelta,&dwRealRead,NULL)){
        cout<<"WriteFile Faield!"<<endl;
        goto Error;
    }
    cout<<"Delta Data:"<<dwRealRead<<" bytes write."<<endl;


    //原来的节块
    if(!WriteFile(hFile,pPrevSec,dwSizePrevSec,&dwRealRead,NULL)){
        cout<<"WriteFile Faield!"<<endl;
        goto Error;
    }
    cout<<"Section Blocks:"<<dwRealRead<<" bytes write."<<endl;

    //增加的节块
    if(!WriteFile(hFile,pAddSec,dwSizeAddSec,&dwRealRead,NULL)){
        cout<<"WriteFile Faield!"<<endl;
        goto Error;
    }
    cout<<"Section Blocks:"<<dwRealRead<<" bytes write."<<endl;
    cout<<"Requeried Works Success Completed."<<endl;

Error:
    CloseHandle(hFile);
    delete[]ppISH;       
    delete[]pDos;
    delete[]pNT;
    delete[]pSecH;
    delete[]pDelta;
    delete[]pPrevSec;
    delete[]pAddSec;
    return 0;
}

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值