HanDs
管理员

[Visual Studio文章] PE加节代码 



工作需要,写了个加节代码。网上有个汇编的,考虑不太周全。
感谢看雪宝图,感谢小伟同学。上代码:

////////////////////////////////////////////////////////
//        PE 加节的函数
//        strFilePath为要改动的文件路径
//        strSecFilePath为节文件,节文件里面是新加节的内容。
//        省略了一些错误处理过程,比如fread失败等
//
//        by Fypher
//        http://hi.baidu.com/nmn714
//
bool addSection(char* strFilePath, char* strSecFilePath)
{
    //打开要改动的文件
    FILE *fFile = fopen(strFilePath,"rb+");
    if(!fFile)
    {
        return false;
    }
    //打开节文件
    FILE *fSec = fopen(strSecFilePath,"rb");
    if(!fSec)
    {
        fclose(fFile);
        return false;
    }
    //读取PE文件头:
    DWORD dwPE_Header_OffSet;
    fseek(fFile,0x3C,SEEK_SET);
    fread(&dwPE_Header_OffSet,1,4,fFile);
   
    IMAGE_NT_HEADERS PE_Header;
    DWORD Head_Len = sizeof(IMAGE_NT_HEADERS);
    fseek(fFile,dwPE_Header_OffSet,SEEK_SET);
    fread(&PE_Header,1,Head_Len,fFile);

    //判断是否有效的PE文件
    if(PE_Header.Signature != IMAGE_NT_SIGNATURE)
    {
        fclose(fFile);
        fclose(fSec);
        return false;
    }

    //计算新节的偏移地址:
    DWORD dwMySectionOffSet = dwPE_Header_OffSet;
    dwMySectionOffSet += 0x4;        //sizeof("PE\0\0")
    dwMySectionOffSet += sizeof(IMAGE_FILE_HEADER);
    dwMySectionOffSet += sizeof(IMAGE_OPTIONAL_HEADER32);
    dwMySectionOffSet += PE_Header.FileHeader.NumberOfSections * 0x28;    //NumberOfSections * sizeof(IMAGE_SECTION_HEADER)

    //检查PE头的空间够不够大
    if(dwMySectionOffSet + 0x28 > PE_Header.OptionalHeader.SizeOfHeaders)
    {
        //空间不够,这里的处理方法是直接返回false
        fclose(fFile);
        fclose(fSec);
        return false;
    }

    //读取新节位置处的内容,本该是全0
    BYTE oldBuff[0x28];
    fseek(fFile,dwMySectionOffSet,SEEK_SET);
    fread(oldBuff,1,0x28,fFile);
    for(int i=0;i!=0x28;++i)
    {
        if(oldBuff[i])
        {
            //竟然不是0?说明这个空间已经被那什么延迟加载占用了
            //只有抹掉image_directory_entry_bound_im,腾出空间。
            //此处严重感谢小伟同学
            BYTE zeroBuff[8] = {0};
            fseek(fFile,dwPE_Header_OffSet + 0xD0,SEEK_SET);
            fwrite(zeroBuff,1,8,fFile);
            break;
        }
    }
   
    //从节文件中获取新节的长度
    fseek(fSec,0,SEEK_END);
    DWORD secLength = ftell(fSec);

    //填充新节的信息
    IMAGE_SECTION_HEADER mySec = {0};

    //新节的名字,暂时叫.ns吧
    mySec.Name[0]='.';
    mySec.Name[1]='n';
    mySec.Name[2]='s';
    mySec.Misc.VirtualSize = secLength;
   
    //新节的RVA
    mySec.VirtualAddress = PE_Header.OptionalHeader.SizeOfImage;

    //SizeOfRawData在EXE文件中是对齐到FileAlignMent的整数倍的值
    mySec.SizeOfRawData = secLength;
    mySec.SizeOfRawData /= PE_Header.OptionalHeader.FileAlignment;
    mySec.SizeOfRawData++;
    mySec.SizeOfRawData *= PE_Header.OptionalHeader.FileAlignment;
    

    //从节文件中读新节的内容
    fseek(fSec,0,SEEK_SET);  
    BYTE* secBuff = (BYTE*)malloc(mySec.SizeOfRawData);
    memset(secBuff,0,mySec.SizeOfRawData);
    fread(secBuff,1,secLength,fSec);

    //读最后一节的SizeOfRawData以及PointerToRawData
    //用来计算新节的PointerToRawData,即文件结束位置
    DWORD dwLastSection_SizeOfRawData,dwLastSection_PointerToRawData;
    fseek(fFile,dwMySectionOffSet - 0x18,SEEK_SET);   
    fread(&dwLastSection_SizeOfRawData,1,4,fFile);
    fread(&dwLastSection_PointerToRawData,1,4,fFile);
   
    //文件结束位置
    DWORD endPosition = dwLastSection_SizeOfRawData + dwLastSection_PointerToRawData;
   
    //按理说,文件应该在这个地方结束,但是也有可能有人硬加了垃圾在末尾,
    //比如或劣质的捆绑技术。因此得把差值算出来
    fseek(fFile,0,SEEK_END);
    DWORD fileLength = ftell(fFile);
    DWORD deltaLength = fileLength - endPosition;    //deltaLength就是垃圾长度。


    //设置新节的 PointerToRawData
    mySec.PointerToRawData = endPosition + deltaLength;
   
    //设置新节的属性
    mySec.Characteristics = 0x0E0000020;        //可读可写可执行

    //写入新节的信息
    fseek(fFile,dwMySectionOffSet,SEEK_SET);
    fwrite(&mySec,1,sizeof(IMAGE_SECTION_HEADER),fFile);

    //增加NumberOfSections
    WORD sections = PE_Header.FileHeader.NumberOfSections + 1;
    fseek(fFile,dwPE_Header_OffSet + 0x06,SEEK_SET);
    fwrite(&sections,1,2,fFile);

    //增加SizeOfImage
    DWORD sizeOfImage = PE_Header.OptionalHeader.SizeOfImage;
    sizeOfImage +=
        (mySec.Misc.VirtualSize/PE_Header.OptionalHeader.SectionAlignment + 1)
        * PE_Header.OptionalHeader.SectionAlignment;
    fseek(fFile, dwPE_Header_OffSet + 0x50, SEEK_SET);
    fwrite(&sizeOfImage, 1, 4, fFile);

    //在文件的最后写入我们的新节具体内容
    fseek(fFile,0,SEEK_END);
    fwrite(secBuff,1,mySec.SizeOfRawData,fFile);
   
    //结束
    free(secBuff);
    fclose(fFile);
    fclose(fSec);
    return true;
}

不用CreateFile、ReadFile等函数是故意的,为了不调用API。因为工作平台是Linux。


学习中请遵守法律法规,本网站内容均来自于互联网,本网站不负担法律责任
PE 加节代码
#1楼
发帖时间:2016-7-9   |   查看数:0   |   回复数:0
游客组
快速回复